I am trying to resize the column width of a datagrid with a converter. For testing, I have a tets application that has a checkbox to tell if use the value of the converter or not. And a textbox to tell which is the width to apply.
When I modify the checkbox or the textbox, the properties of the view model are notified, but the converter is not fired.
My code is this:
Main windows:
<Window x:Class="ModificarColumnaDataGrid.MainWindow"
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:ModificarColumnaDataGrid"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<local:ucControlUsuario HorizontalAlignment="Stretch" Margin="0,0,0,0" VerticalAlignment="Stretch"/>
</Grid>
</Window>
User control:
<UserControl x:Class="ModificarColumnaDataGrid.ucControlUsuario"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:ModificarColumnaDataGrid"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<ResourceDictionary>
<!--Este diccionario, el GUI, tendrá la configuración general para los diferentes elementos que se tengan en la GUI.-->
<ResourceDictionary.MergedDictionaries>
<!--Ruta relativa, porque esta vista está en subdirectorio, al mismo nivel que recursos.-->
<ResourceDictionary Source="DiccionarioRecursos.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<CheckBox Content="Use Converter" HorizontalAlignment="Left" Margin="0,10,0,0" VerticalAlignment="Top"
IsChecked="{Binding UseConverterIsChecked}"/>
<TextBox Text="{Binding WidthColumn2, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Left" Margin="106,48,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
<!--Necesario para poder acceder a las propiedades del datacontext, necesario para los datatriggers.-->
<FrameworkElement x:Name="ProxyElement" Visibility="Collapsed"/>
<DataGrid Margin="0,154,0,0" AutoGenerateColumns="false">
<DataGrid.Columns>
<DataGridTextColumn Header="Columna1" Width="200"/>
<DataGridTextColumn Header="Columna2" Width="200">
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<!--<Setter Property="Width" Value="20"/>-->
<Setter Property="Width">
<Setter.Value>
<MultiBinding Converter="{StaticResource MiMultiValueConverter}" >
<Binding Source="{x:Reference ProxyElement}" Path="DataContext.UseConverterIsChecked" />
<Binding Source="{x:Reference ProxyElement}" Path="DataContext.WidthColumn2" />
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="Columna3" Width="200"/>
</DataGrid.Columns>
</DataGrid>
<Label Content="Pixels column 2" HorizontalAlignment="Left" Margin="0,44,0,0" VerticalAlignment="Top"/>
</Grid>
</UserControl>
Code behind of user control:
namespace ModificarColumnaDataGrid
{
/// <summary>
/// Lógica de interacción para ucControlUsuario.xaml
/// </summary>
public partial class ucControlUsuario : UserControl
{
public ucControlUsuario()
{
InitializeComponent();
DataContext = new ucControlUsuarioViewModel();
}
}
}
View model of user control:
namespace ModificarColumnaDataGrid
{
class ucControlUsuarioViewModel : BaseViewModel
{
private bool _useConverterIsChecked;
public bool UseConverterIsChecked
{
get { return _useConverterIsChecked; }
set
{
_useConverterIsChecked = value;
base.RaisePropertyChangedEvent(nameof(UseConverterIsChecked));
}
}
private double _widthColumn2;
public double WidthColumn2
{
get { return _widthColumn2; }
set
{
_widthColumn2 = value;
base.RaisePropertyChangedEvent(nameof(WidthColumn2));
}
}
}
}
View model base:
public abstract class BaseViewModel : INotifyPropertyChanging, INotifyPropertyChanged { #region INotifyPropertyChanging Members
public event PropertyChangingEventHandler PropertyChanging;
#endregion
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
#region Administrative Properties
/// <summary>
/// Whether the view model should ignore property-change events.
/// </summary>
public virtual bool IgnorePropertyChangeEvents { get; set; }
#endregion
#region Public Methods
//@#ESTUDIAR: si esta implemantación es mejor.
//Este método tiene la ventaja de que en el set de la propiedad, con poner OnPropertyChanged() es suficiente, no hace falta
//pasar por parámetro ni el stirng con el nombre de la propiedad ni siquiera la propiedad, porque la coge por defecto.
//Pero se puede pasar la propiedad en caso de que quiera notificar fuera del set, pero no hace falta pasar el string, sino la
//propiedad, por lo que el mantenimiento es mucho mejor.
////////////public void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string paramStrNombrePropiedad = "")
////////////{
//////////// PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(paramStrNombrePropiedad));
////////////}
/// <summary>
/// Raises the PropertyChanged event.
/// </summary>
/// <param name="propertyName">The name of the changed property.</param>
public virtual void RaisePropertyChangedEvent(string propertyName)
{
// Exit if changes ignored
if (IgnorePropertyChangeEvents) return;
// Exit if no subscribers
if (PropertyChanged == null) return;
// Raise event
var e = new PropertyChangedEventArgs(propertyName);
PropertyChanged(this, e);
}
/// <summary>
/// Raises the PropertyChanging event.
/// </summary>
/// <param name="propertyName">The name of the changing property.</param>
public virtual void RaisePropertyChangingEvent(string propertyName)
{
// Exit if changes ignored
if (IgnorePropertyChangeEvents) return;
// Exit if no subscribers
if (PropertyChanging == null) return;
// Raise event
var e = new PropertyChangingEventArgs(propertyName);
PropertyChanging(this, e);
}
#endregion
}
Dicccionario de recursos:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:conv="clr-namespace:ModificarColumnaDataGrid"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<conv:MiMultiValueConverter x:Key="MiMultiValueConverter" />
</ResourceDictionary>
Multivalue converter:
namespace ModificarColumnaDataGrid
{
public class MiMultiValueConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
return 20;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
How could I make the converter be fired?
EDIT:
I have tried to set the width of the column istead of the textblock of the style:
<DataGridTextColumn.Width>
<MultiBinding Converter="{StaticResource MiMultiValueConverter}" >
<Binding Source="{StaticResource BindingProxy}" Path="Data.UseConverterIsChecked"/>
<Binding Source="{StaticResource BindingProxy}" Path="Data.WidthColumn2" />
</MultiBinding>
</DataGridTextColumn.Width>
But it doesn't work too.
However, if I use a converter directly in the Width property of the column it works:
<DataGridTextColumn Header="Columna2"
Width="{Binding Data.UseConverterIsChecked, Converter={StaticResource MiValueConverter}, Source={StaticResource BindingProxy}}">
The problem with thi solution is that I need a multivalue converter, and I don't know how to use it in the width property of the column.
Thanks.
The problem with thi solution is that I need a multivalue converter, and I don't know how to use it in the width property of the column.
Just set the Width
property using object element syntax:
<DataGridTextColumn Header="Columna2">
<DataGridTextColumn.Width>
<MultiBinding Converter="{StaticResource MiValueConverter}">
<Binding Path="Data.UseConverterIsChecked" Source="{StaticResource BindingProxy}" />
<!-- add more bindings here -->
</MultiBinding>
</DataGridTextColumn.Width>
</DataGridTextColumn>