how to pass current Combobox item in converter in a style - wpf

I am trying to create a style for comboxitem. I want to pass the current comboboxitem to converter. Style is like
<Style x:Key="MyVisibilityStyle" TargetType="{x:Type ComboBoxItem}">
<Setter Property="Visibility">
<Setter.Value>
<MultiBinding Converter="{StaticResource VisibiltyMultiValueConverter}">
<Binding Path="."/>
<Binding Path="SelectedItem"
ElementName="ABCComboBox"/>
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
Problem is the "." is passing the object of MainWindow not the comboboxitem.

Through <Binding Path="."> youre passing the object which the ComboBoxItem holds, but with <Binding RelativeSource="{RelativeSource Self}"/> you can pass the control itself.
What you also could do is passing the whole ComboBox and its selected index/item:
and in your converter you could get your ComboBoxItem like so:
ComboBoxItem cbi = (ComboBoxItem)(cb.ItemContainerGenerator.ContainerFromIndex(selectedindex));
or
ComboBoxItem cbi = (ComboBoxItem)(cb.ItemContainerGenerator.ContainerFromItem(selecteditem));

You can get the selected item of the combobox by using FindAncestor:
<Binding Path="SelectedItem" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=ComboBox}"/>

Related

Whis is the column not resize?

I have a datagrid and I want to set the width of a column according to some values, so I am trying to use a multibinding in this way:
<DataGridTextColumn.Width>
<MultiBinding Converter="{StaticResource MyMultiValueConverter}">
<Binding Source="{x:Reference ProxyElement}" Path="DataContext.MyProperty" />
<Binding Source="0"/>
</MultiBinding>
</DataGridTextColumn.Width>
The converter is fired, but the width is not changed according to de value it returns.
However, I have a similiar converter to set the visibility and it works as expected:
<DataGridTextColumn.Visibility>
<MultiBinding Converter="{StaticResource MyConverterVisibilityMultiValueConverter}">
<Binding Source="{x:Reference ProxyElement}" Path="DataContext.NombreProveedor" />
<Binding Source="0"/>
</MultiBinding>
</DataGridTextColumn.Visibility>
Why does it work with the visibivilty but not with the width?
Thanks.
EDIT:
I have tried setting the width of the textblock inside the column in this way:
Value converter:
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.SizeToHeader);
return 20;
}
Xaml: Option 1, setting the width directly, it works
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Width" Value="20"/>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
Xaml: option 2: trying with value converter, it doesn't work
<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 and it returns 20, but the column doesn't take this value.
Ensure that the converter returns a DataGridLength value:
return new DataGridLength(100, DataGridLengthUnitType.Pixel);

Remove white space from MultiBinding StringFormat

Unable to remove whitespace from StringFormat.
If no 'Type' data the following whitespace doesn't fallback.
ReleaseDate, space, space, dot, space, space, Type, space (some reason it doesn't remove this space), Color
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0:yyyy} · {1} {2}" >
<Binding Path="ReleaseDate" FallbackValue="{x:Null}"/>
<Binding Path="Type" FallbackValue="{x:Null}"/>
<Binding Path="Color" FallbackValue="{x:Null}"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
You may probably replace the MultiBinding and its StringFormat by a DataTrigger:
<TextBlock>
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Text">
<Setter.Value>
<MultiBinding StringFormat="{}{0:yyyy} · {1} {2}" >
<Binding Path="ReleaseDate" FallbackValue="{x:Null}"/>
<Binding Path="Type"/>
<Binding Path="Color" FallbackValue="{x:Null}"/>
</MultiBinding>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding Type}" Value="{x:Null}">
<Setter Property="Text">
<Setter.Value>
<MultiBinding StringFormat="{}{0:yyyy} · {1}" >
<Binding Path="ReleaseDate" FallbackValue="{x:Null}"/>
<Binding Path="Color" FallbackValue="{x:Null}"/>
</MultiBinding>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
While the approach with DataTrigger works, it is very verbose. I would make it a two-step process: bind Type separately with a StringFormat which has a space, then bind everything together
<TextBlock Name="Title"
local:Attached.SomeString="{Binding Type,
StringFormat='\{0} ',
TargetNullValue=''}">
<TextBlock.Text>
<MultiBinding StringFormat="{}{0:yyyy} · {1}{2}">
<Binding Path="Login" />
<Binding Path="(local:Attached.SomeString)"
RelativeSource="{RelativeSource Self}" />
<Binding Path="Name" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
If Type is not null then SomeString binding uses string format, and returns Type + space at the end. If Type is null, then binding return empty string.
SomeString is a reusable attached dependency property without special meaning. It declared as
public class Attached
{
public static readonly DependencyProperty SomeStringProperty =
DependencyProperty.RegisterAttached("SomeString", typeof (string), typeof (Attached));
public static void SetSomeString(UIElement element, string value)
{
element.SetValue(SomeStringProperty, value);
}
public static string GetSomeString(UIElement element)
{
return (string)element.GetValue(SomeStringProperty);
}
}
TextBlock has Tag property which can be used to store (or bind) some data, but Tag is of type object, and doesn't use StringFormat from binding. So I couldn't use Tag for my purpose here, and had to create another property, which has string type. (note also special syntax to bind attached property)

Overriding DataGridRow style for CodedUI testing produces undesirable appearance

Due to some shortcomings with CodedUI, it's difficult to select items in the DataGrid. One work around that I've found is to override the ItemContainerStyle like so:
<DataGrid.ItemContainerStyle>
<Style TargetType="{x:Type DataGridRow}">
<Setter Property="AutomationProperties.AutomationId">
<Setter.Value>
<MultiBinding StringFormat="ArisingID_{0}">
<Binding Path="(DataGridRow.Tag)" RelativeSource="{RelativeSource Mode=Self}" />
</MultiBinding>
</Setter.Value>
</Setter>
<Setter Property="AutomationProperties.Name">
<Setter.Value>
<MultiBinding StringFormat="ArisingID_{0}">
<Binding Path="(DataGridRow.Tag)" RelativeSource="{RelativeSource Mode=Self}" />
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
</DataGrid.ItemContainerStyle>
and then populate each Row.Tag with a unique ID in the code behind:
private void MyDataGrid_OnLoadingRow(object sender, DataGridRowEventArgs e)
{
var item = e.Row.Item as IMyViewModel;
e.Row.Tag = item.UniqueSeqId;
}
However, one issue is that this overrides some of the "default style" of the data grid row - each cell on the data grid seems to be separately selectable, rather than it behaving as just one row.
What's the best way to incorporate the default styles along with these modifications?
There is a BasedOn property that will set your style, and then add the extra setters you've added:
<DataGrid.ItemContainerStyle>
<Style TargetType="{x:Type DataGridRow}" BasedOn="{StaticResource DataGridRowStyle}">
<Setter Property="AutomationProperties.AutomationId">
<Setter.Value>
<MultiBinding StringFormat="ArisingID_{0}">
<Binding Path="(DataGridRow.Tag)" RelativeSource="{RelativeSource Mode=Self}" />
</MultiBinding>
</Setter.Value>
</Setter>
<Setter Property="AutomationProperties.Name">
<Setter.Value>
<MultiBinding StringFormat="ArisingID_{0}">
<Binding Path="(DataGridRow.Tag)" RelativeSource="{RelativeSource Mode=Self}" />
</MultiBinding>
</Setter.Value>
</Setter>
</Style>

WPF XamComboBox DisplayMemberPath with concatenated values

I have the following code -
<igEditors:XamComboEditor ItemsSource="{Binding Instances}"
Margin="5,2,5,2" Width="175" HorizontalAlignment="Left"
SelectedItem="{Binding SelectedInstance,Mode=TwoWay,NotifyOnValidationError=True,ValidatesOnDataErrors=True,ValidatesOnExceptions=True}"
>
<igEditors:XamComboEditor.ComboBoxStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} ({1})">
<Binding Path="Name" />
<Binding Path="Id" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</igEditors:XamComboEditor.ComboBoxStyle>
</igEditors:XamComboEditor>
When I set the SelectedInstance from my viewmodel, the combobox is displaying the type of the object. If I then make a selection, it displays correctly, but I click out of the combobox, losing focus, it reverts back to the object type. If I set the DisplayMemberPath manually to just Name, it works correctly, but I really need it to be a concatenated value for the displaymemberpath.
Can anyone help?
Thanks
The answer to this question was to use the ValueToDisplayTextConverter along with a custom converter. More details can be found here -
http://www.infragistics.com/community/forums/p/77378/390782.aspx

Current datagrid item and multibinding

I have a DataGrid, in which I want to change the background of a row according to the values of the ItemSource, so I need to pass the current item, but I don't know how.
I am doing that:
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Setter Property="Background">
<Setter.Value>
<MultiBinding Converter="{StaticResource myDataGridBackgroundMultiValueConverter}">
<MultiBinding.Bindings>
<Binding ElementName="ucPrincipal" Path="DataContext.MyProperty01FromDataContext"/>
<Binding ElementName="ucPrincipal" Path="DataContext.MyProperty02FromDataContext"/>
<Binding ElementName="ucPrincipal" Path="DataContext.MyProperty03FromDataContext"/>
<Binding ElementName="dgdMyGrid" Path="CurrentItem"/>
</MultiBinding.Bindings>
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
</DataGrid.RowStyle>
The DataGrid has as ItemsSource a collection of MyDataClass (that has many properties) in the ViewModel. I need to pass to the converter the MyDataClass with the information of the row.
CurrentItem does not work, because I always receive null.
All the other parameters are ok.
DataGrid has no CurrentItem property, only CollectionViews have, DataGrid has a SelectedItem. You should see a binding error because of this as well.
If by current item you mean the data item to which the styled row belongs that would be the DataContext of the current row, which can be targeted via <Binding />.
Well, finnally, I get the way to pass the dataContext of the row to the converter. I do the following:
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Setter Property="Visibility" Value="{Binding ChangeTracker.State, Converter={StaticResource visibilidadFilaBorradaConverter}}"/>
<Setter Property="Background">
<Setter.Value>
<MultiBinding Converter="{StaticResource ucTareasMatenimientoDataGridBackgroundMultiValueConverter}">
<MultiBinding.Bindings>
<Binding ElementName="ucPrincipal" Path="DataContext.Property01"/>
<Binding Path="DataContext" RelativeSource="{RelativeSource Mode=Self}" />
<Binding ElementName="ucPrincipal" Path="DataContext.Property02"/>
<Binding ElementName="ucPrincipal" Path="DataContext.Property03"/>
<Binding ElementName="ucPrincipal" Path="DataContext.Property04"/>
</MultiBinding.Bindings>
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
</DataGrid.RowStyle>
In the second parameter for the multivalue converter, I use the RelativeSource, to be able to pass the datContext of the row. In this way, I can compare its information with other properties of the principal dataContext of the control.

Resources