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

ComptonAlvaro 166 Reputation points
2021-10-23T15:14:59.473+00:00

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 Presentation Foundation
Windows Presentation Foundation
A part of the .NET Framework that provides a unified programming model for building line-of-business desktop applications on Windows.
2,671 questions
0 comments No comments
{count} votes

Accepted answer
  1. Peter Fleischer (former MVP) 19,231 Reputation points
    2021-10-23T18:13:24.62+00:00

    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 person found this answer helpful.

1 additional answer

Sort by: Most helpful
  1. ComptonAlvaro 166 Reputation points
    2021-10-24T07:46:24.863+00:00

    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.