question

ComptonAlvaro avatar image
0 Votes"
ComptonAlvaro asked ComptonAlvaro commented

Why the column is not resize with the multi value converter?

I want to use a multi value converter to set the dinamically the width of a column.

For testing purposes, the multivalue converter just set 20 as width, a very low value to see if the value is used.

 public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
 {
 //I have tried both ways, DataGridLength and return 20
     //return new DataGridLength(20, DataGridLengthUnitType.Pixel);
     return 20;
 }


In this code I tried to use return directly 20 and also I have tried to return a DataGridLength, in both cases, it doesn't work.


I have tried a simple xaml code that I set the width directly (no using the converter), in the DataGridTextColumn.ElementStyle, in this way.

                 <DataGridTextColumn.ElementStyle>
                     <Style TargetType="{x:Type TextBlock}">
                         <Setter Property="Width" Value="20"/>
                     </Style>
                 </DataGridTextColumn.ElementStyle>
             </DataGridTextColumn>

In this case, it works, if I set the width of the textblock in the elemet style.

So next step I have tried using the converter, in this way:

             <DataGridTextColumn.ElementStyle>
                 <Style TargetType="{x:Type TextBlock}">
                     <Setter Property="Width">
                         <Setter.Value>
                             <MultiBinding Converter="{StaticResource MyMultiValueConverter}" >
                                 <Binding Source="{x:Reference ProxyElement}" Path="DataContext.Property1" />
                                 <Binding Source="{x:Reference ProxyElement}" Path="DataContext.Property2" />
                             </MultiBinding>
                         </Setter.Value>
                     </Setter>
                 </Style>
             </DataGridTextColumn.ElementStyle>
         </DataGridTextColumn>

The converter is rised, but the value 20 that is returned by the converter it doesn't used, so the column is not resized.

How could I use a multivalue converter to set the width of a column?



Thanks.


windows-wpf
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

PeterFleischer-3316 avatar image
1 Vote"
PeterFleischer-3316 answered ComptonAlvaro commented

Hi,
I think, your ProxyElement doesn't detect PropertyChanged. My demo works fine, try it.

XAML:

 <Window x:Class="WpfApp1.Window074"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
         xmlns:local="clr-namespace:WpfApp074"
         mc:Ignorable="d"
         Title="Window074" Height="450" Width="800">
   <Window.Resources>
     <local:ViewModel x:Key="vm"/>
     <local:MyMultiValueConverter x:Key="MyMultiValueConverter"/>
   </Window.Resources>
   <StackPanel DataContext="{StaticResource vm}">
     <TextBox Text="{Binding WidthValue}"/>
     <CheckBox IsChecked="{Binding WidthDefault}" Content="Default Width"/>
     <DataGrid ItemsSource="{Binding View}" AutoGenerateColumns="False">
       <DataGrid.Columns>
         <DataGridTextColumn Header="Col1" Binding="{Binding SomeString}">
           <DataGridTextColumn.ElementStyle>
             <Style TargetType="{x:Type TextBlock}">
               <Setter Property="Width">
                 <Setter.Value>
                   <MultiBinding Converter="{StaticResource MyMultiValueConverter}">
                     <Binding Path="WidthValue" Source="{StaticResource vm}"/>
                     <Binding Path="WidthDefault" Source="{StaticResource vm}"/>
                   </MultiBinding>
                 </Setter.Value>
               </Setter>
             </Style>
           </DataGridTextColumn.ElementStyle>
         </DataGridTextColumn>
       </DataGrid.Columns>
     </DataGrid>
   </StackPanel>
 </Window>

Code:

 using System;
 using System.Collections.ObjectModel;
 using System.ComponentModel;
 using System.Globalization;
 using System.Runtime.CompilerServices;
 using System.Windows;
 using System.Windows.Data;
    
 namespace WpfApp074
 {
   public class ViewModel : INotifyPropertyChanged
   {
     public ViewModel()
     {
       ObservableCollection<Data> col = new ObservableCollection<Data>();
       for (int i = 1; i < 10; i++) col.Add(new Data() { SomeString = $"Row {i}" });
       cvs.Source = col;
     }
     private CollectionViewSource cvs = new CollectionViewSource();
     public ICollectionView View { get => cvs.View; }
    
     private double _widthValue = 20;
     public double WidthValue
     {
       get => this._widthValue;
       set { this._widthValue = value; OnPorpertyChanged(); }
     }
    
     private bool _widthDefault = false;
     public bool WidthDefault
     {
       get => this._widthDefault;
       set { this._widthDefault = value; OnPorpertyChanged(); }
     }
    
     public event PropertyChangedEventHandler PropertyChanged;
     internal void OnPorpertyChanged([CallerMemberName] string propName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
    
   }
    
   public class Data
   {
     public string SomeString { get; set; }
   }
    
   public class MyMultiValueConverter : IMultiValueConverter
   {
     public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
     {
       double w = 100;
       if (!(bool)values[1]) double.TryParse(values[0].ToString(), out w);
       return w;
     }
    
     public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
     {
       throw new NotImplementedException();
     }
   }    
 }


· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Thanks so much for the answer. It works good.

0 Votes 0 ·
ComptonAlvaro avatar image
0 Votes"
ComptonAlvaro answered PeterFleischer-3316 edited

Thanks for your example, it is good to know another way to do it.

ABout the proxy, it works, because when I debug and set a breakpoint in the converter, the 2 properties have the value that I expect. So it is true that I seems I have a problem with the converter, but I think that is not because of the proxy.

Also, the converter is rised and in the test I return just the value 20, so it desn't use the parameters of the multibinding.

NOTE: when I try to use this:

<local:ViewModel x:Key="vm"/>

I get an error that says it doesn't exist in the namespace local.

I am using a usercontrol, not a windows, could it be this the reason of the error?


NOTE: I have created a simple project to recreate the problem and it is true that to bindings doesn't make to fire the converter. I will try your solution to see.


Thanks so much.

· 7
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

<local:ViewModel x:Key="vm"/>

I get an error that says it doesn't exist in the namespace local.

See my code:

  <Window x:Class="WpfApp1.Window074"
 ...
          xmlns:local="clr-namespace:WpfApp074"
    
 and
    
  namespace WpfApp074
  {
    public class ViewModel : INotifyPropertyChanged





0 Votes 0 ·

I could solve the problem, the converter is not fired.

I am not sure if it could be possible to upload the application to OneDrive, so you could check the code and see?


Thanks so much.

0 Votes 0 ·

What I don't see is how do you set the view model of the view.

I am using this code:

<Window.DataContext>
<local:ViewModel/>
</Window.DataContext>

0 Votes 0 ·

Hi,
in this case you automatically instantiate ViewModel in Window and it's difficult to use the same instance in following code:

                <MultiBinding Converter="{StaticResource MyMultiValueConverter}">
                  <Binding Path="WidthValue" Source="{StaticResource vm}"/>
                  <Binding Path="WidthDefault" Source="{StaticResource vm}"/>
                </MultiBinding>
0 Votes 0 ·

Hi,
if you use automatically created instance of ViewModel in Window you must point to this instance in following XAML like this:

               <MultiBinding Converter="{StaticResource MyMultiValueConverter}">
                 <Binding Path="DataContext.WidthValue" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}"/>
                 <Binding Path="DataContext.WidthDefault" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}"/>
               </MultiBinding>
0 Votes 0 ·

I have realized that it is needed to set the datacontext in the stackpanel to work. If I set the datacontext in the window, it doesn't work.

So I am wondering, if the windows need to access to some property of the view model, would it be able to access it? Because normally I use to set the view model of the view in the code behind of the windows or user control.

0 Votes 0 ·

Hi,
normally I use MVVM pattern und there's no code behind. In XAML a instance will be automatically created. The easiest way to use the same instance is to use StaticResource. Once StaticResource is created the next using use the same instance.

0 Votes 0 ·