I am trying to create converter that shows me if something got value is Other then "None" just write X in cell so I have created simple element style:
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Text" Value="{Binding Value, Converter={StaticResource SetBitConverter}}"/>
</Style>
</DataGridTextColumn.ElementStyle>
And converter is as well simple
public class SetBitConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var input = value as string;
switch (input)
{
case "None":
return "OK";
default:
return "X";
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotSupportedException();
}
}
Now problem is that on value set it will not enter converter, although if i change property from Text to Background for example, it will enter converter with no problem.
The value applied by a Style will always be of lower priority than one that has been set directly or, as in your case, by a Binding. If you want to add a Converter, add it to the Binding property of the DataGridTextColumn or use a DataGridTemplateColumn instead.
E.g.:
<DataGridTextColumn Binding="{Binding Value, Converter={StaticResource SetBitConverter}}"/>
Here is a comparison of the auto-generated default column and the one from above:
Why does dependency property precedence exist?
Typically, you would not want styles to always apply and to obscure even a locally set value of an individual element (otherwise, it would be very difficult to use either styles or elements in general). Therefore, the values that come from styles operate at a lower precedent than a locally set value.
Technical Background on Value Precedence
Property system coercion
Active animations, or animations with a Hold behavior
Local value
TemplatedParent template properties
Implicit style
Style triggers
Template triggers
Style setters
Default (theme) style
Inheritance
Default value from dependency property metadata
Related
In my application I want to switch between editing and just displaying data in my view.
In order to edit them I have textboxes. For Displaying I am using textblock.
Some of the Data is displayed inside a ListView.
In my ViewModel I have variables called "IsEditingMode" and "IsNotEditingMode" to determine the state of the view.
Now I want something like this in wpf:
<switch betwen implementation>
<use textbox if IsEditingMode>
<use textblock if IsNotEditingMode>
I tried this using Converters to change the Visibility of the textbox and the textblock:
Converter:
public class BoolToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var boolValue = (bool)value;
if (boolValue)
return Visibility.Visible;
return Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Provide the Converter a Resource:
<helper:BoolToVisibilityConverter x:Key="IsVisibleConverter"/>
Use the converter to change the Visibility of the elements in my xaml:
<StackPanel>
<TextBlock Text ="{Binding TextVariableInVM}" Visibility="{Binding IsNotEditingMode, Converter={StaticResource IsVisibleConverter}}"/>
<TextBox Text ="{Binding TextVariableInVM}"
Visibility="{Binding IsEditingMode,
Converter={StaticResource IsVisibleConverter}}"/>
</StackPanel>
The result is:
Editing mode: The Textbox is displayed
Not editing mode: The TextBlock is displayed
For a small number of displayed variables this is just fine.
In my real application I have a huge amount of displayed variables and some of them are displayed using listview.
In that case my UI is getting really slow.
I believe that this is due to the fact that I bind each variable twice.
Is there a more elegant solution to do that editing <-> not editing switch?
Why not use only a TextBox element for both situations?
TextBox has a property called IsReadOnly that you can set to true or false depending on your action.
Is this code enough for your need's?
It's a TextBox that binds your text, and changes from edit mode or not.
<TextBox Text="{Binding TextVariableInVM}" IsReadOnly="{Binding IsNotEditingMode}"/>
If you complain about UI being slow, this example will be faster and more elegant because:
Doesn't need a StackPanel
One text element instead of two
Just one extra property needed to check if is editable or not
Doesn't need to convert from Boolean to Visibility
You may also want to remove the TextBox Border when it is read-only by a Style like this:
<Style TargetType="TextBox">
<Style.Triggers>
<Trigger Property="IsReadOnly" Value="True">
<Setter Property="BorderBrush" Value="{x:Null}"/>
</Trigger>
</Style.Triggers>
</Style>
I want to check that the ListBox element has a specific type to assign a visual style to, but the constant check fails. Maybe I'm doing it wrong?
Problem with this line:
Condition Binding="{Binding}" Value="{x:Type econemodels:DishDTOAdvance}"
<ListBox.ItemTemplate>
<DataTemplate>
<ContentControl Content="{Binding}">
<ContentControl.Style>
<Style TargetType="ContentControl">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding}"
Value="{x:Type econemodels:DishDTOAdvance}" />
</MultiDataTrigger.Conditions>
<Setter Property="ContentTemplate"
Value="{StaticResource DishNoImage}" />
</MultiDataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</DataTemplate>
</ListBox.ItemTemplate>
The binding fails, because it binds an instance of type DishDTOAdvance and compares it with an instance of Type that describes the DishDTOAdvance type. Obviously they are different types and the condition is never true. In XAML x:Type is like typeof() or GetType() in code.
The x:Type markup extension has a similar function to the typeof() operator in C# or the GetType operator in Microsoft Visual Basic. The x:Type markup extension supplies a from-string conversion behavior for properties that take the type Type.
That is exactly the case for a custom DataTemplateSelector, no need for bindings.
Provides a way to choose a DataTemplate based on the data object and the data-bound element.
With a data template selector you can provide arbitrary logic to choose a data template for an item. In your case a switch statement for the type is enough to choose a template that can be found through FindResource in the resources up the visual tree. Of course you could also assign data templates trough properties if you do not want to search in all resources.
public class TypeTemplateSelector : DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
var contentPresenter = (ContentPresenter)container;
switch (item)
{
case DishDTOAdvance _:
return (DataTemplate)contentPresenter.FindResource("DishNoImage");
// ...other type cases.
default:
return base.SelectTemplate(item, container);
}
}
}
Create and add an instance of the data template selector to your ListBox. Remove the ItemTemplate completely, it it now automatically assigned by the selector.
<ListBox ...>
<ListBox.ItemTemplateSelector>
<local:TypeTemplateSelector/>
</ListBox.ItemTemplateSelector>
<!-- ...other markup. -->
</ListBox>
The ContentControl is redundant. However in case you need it within an item template, it works just the same. ContentControl exposes an ContentTemplateSelector property for the same purpose.
Bonus round: Is the trigger impossible? No. You can create a converter that returns the type.
public class TypeConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value?.GetType();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new InvalidOperationException();
}
}
Create an instance of the converter in a resource dictionary in scope.
<Window.Resources>
<local:TypeConverter x:Key="TypeConverter"/>
</Window.Resources>
Use the converter in the condition binding. Now types are compared.
<Condition Binding="{Binding Converter={StaticResource TypeConverter}}"
Value="{x:Type econemodels:DishDTOAdvance}"/>
I have a button control in a WPF application which is used for log-in purposes. The button is dual purpose: when logged-out, it shall display the text "log in". When logged-in, it shall display the text "log out".
I could do this with databinding to an appropriate string property in the viewmodel.
But it would be neater if I could simply databind to the "loggedIn" boolean (false for logged-out, true for logged-in) and then make the decision about what text to display on the button from within the view.
Is this possible?
You can achieve it using Style in Xaml without writing specific C# code.
Suppose you have IsLoggedIn property in ViewModel which is being changed on button bind command's execute method :
private void MyButtonCommandExecuteMethod()
{
this.IsLoggedIn = !this.IsLoggedIn;
}
private bool isLoggedIn;
public bool IsLoggedIn
{
get
{
return this.isLoggedIn;
}
set
{
this.isLoggedIn = value;
OnPropertyChanged(nameof(IsLoggedIn));
}
}
In the above code OnPropertyChanged is method implementation of INotifyPropertyChanged's PropertyChanged event. If you using any framework or defined own name, then replace it with appropriate name.
You could define a style such as:
<Button Command="{Binding YourButtonCommand}">
<Button.Style>
<Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="Content" Value="Log In" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsLoggedIn}" Value="True">
<Setter Property="Content" Value="Log out" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
In the above code IsLoggedIn is bind to DataTrigger to update the Button's Content property based on it's value.
Another point, the button style is inherited from default style. If you any Keyed style then use it in BasedOn Property.
Solution
Yes that is possible using value converter, specifically IValueConverter. You can bind a bool property, say BoolProperty from your viewmodel to button using converter like this.
<Button Content="{Binding BoolProperty, Converter={StaticResource BoolConverter}}" />
Step 1: You need to create a converter that will accept bool value and return whatever string as you wish.
public class BoolConverter : System.Windows.Data.IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is bool)
{
return value.ToString();
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Step 2: Declare this converter as a resource in XAML (you will need to define local namespace alias that contains the converter in your <Window ..> start element.
<local:BoolConverter x:Key="BoolConverter" />
So now whenever property changed event is raised for BoolProperty, this converter will be triggered and button text will change appropriately.
Suggestion:
I am not sure why you think maintaining extra string property is not a clean way. It is clean and is much simpler approach than using converter. Whatever I have shown is unnecessary overhead for your case, IMO. However, since you asked about possibility, I detailed it. Choice is yours! :)
Background:
I have a DataGrid whose ItemSource is bound to an ObservableCollection<Dictionary<string, object>> type. The thought behind this is to allow the DataGrid to display a bunch of objects from different sources (This is a log gathering program so the fields all vary from one type of log to the next). I have taken care of the generation of columns through a behavior so I have no knowledge of what the columns will be until runtime.
The Problem:
I want to have a way to show commonalities between the entries based off a field (column) while maintaining the sort order from a different column. To do this I was thinking of going with a color coding system. If the value in a cellA under columnA matched the value of cellB in columnA, the two rows that the cells belong to would get the same unique color for the values found in both cells. The user should also be able to change the column to color code.
I've been trying to work with a style to get the desired effect but am having some troubles. Here's the code in question.
MainWindow.xaml
<DataGrid...>
<DataGrid.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="Background">
<Setter.Value>
<MultiBinding Converter="{StaticResource RowBackgroundConverter}">
<MultiBinding.Bindings>
<Binding RelativeSource="{RelativeSource Self}"/>
<Binding Path="ColumnName"/>
<Binding Path="."/>
</MultiBinding.Bindings>
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
</DataGrid.CellStyle>
</DataGrid>
RowBackgroundConverter
/// <summary>
/// A converter that changes the background of a DataGrid based on a cell value
/// </summary>
public class RowBackgroundConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (values[0] is DataGridCell)
{
DataGridCell cell= (DataGridCell)values[0];
string columnName = (string)values[1];
Dictionary<string, object> dataGridValues = (Dictionary<string, object>)values[2];
// Check the cell's column name and compare it against the desired column name (columnName) Get the index of the value and get the mapped brush. (dataGridValues[columnName])
return new SolidColorBrush(ColorMap.ColorDictionary[0]);
}
return SystemColors.AppWorkspaceColor;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
And in my ViewModel I have a ColumnName property for the desired column to color code.
The problem is how can I reach a property in my view model when my multibinding's context is the data grid cell?
In case I understand your question correctly, you should be able to get to the ColumnName property by setting the relativesource of the binding to the Window.
This assumes that the DataContext of the Window has been set to the ViewModel that contains the ColumnName property.
Something like this should work:
{Binding Path=DataContext.ColumnName,
RelativeSource={RelativeSource AncestorType=Window}}
I'm trying to add some default text to combo boxes that will show when there is no item selected. I'm using a style to acheive this which works great when the combo is first loaded.
<Style TargetType="{x:Type igRibbon:ComboEditorTool}" x:Key="PleaseSelect">
<Style.Triggers>
<Trigger Property="SelectedIndex" Value="-1">
<Setter Property="Text" Value="Please Select" />
</Trigger>
</Style.Triggers>
</Style>
<igRibbon:ComboEditorTool Style="{StaticResource PleaseSelect}"
ItemsSource="{Binding MyItems}" SelectedItem="{Binding MySelectedItem }" />
But when the combo's selected item is reset (by setting it to null, which sets the SelectedIndex to -1) it fails to display the default text (even though the the trigger does fire), what could be the reason for this? Is there a better way to reset the selected item?
Cheers
Here is the solution that I used, thanks to #AlexPaven for the idea:
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null)
{
return "Please Select";
}
else
{
return value;
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is string && ((string)value) == "Please Select")
{
return null;
}
else
{
return value;
}
}
I'm not familiar with the Infragistics suite, but I suspect it's the same thing as with regular combo boxes: since you have a binding on SelectedItem, the Text cannot be set to an item that blatantly disobeys that binding; the Text IS a representation of the SelectedItem. If the SelectedItem is null, then the Text must also be a representation of null.
I'm guessing (didn't try it and I may be just plain wrong) you could probably accomplish this with an IValueConverter that returns a custom string when the passed object is null (and returns the object unchanged otherwise), set on the SelectedItem binding.
It's been a while since this question was asked, but let me answer it with a more Infragistics related answer.
Let's start with a short side node:
We have to be careful when using XamComboEditor without specifying the namespace,
because in the Infragistics Framework the class is defined two times.
1. Infragistics.Windows.Editors.XamComboEditor
2. Infragistics.Controls.Editors.XamComboEditor
Referring to the Infragistics Help, the recommended one is the Infragistics.Windows.Editors.XamComboEditor
See the About xamComboEditor:
We recommend that you use the xamComboEditor control instead of the xamComboEditor (Input) control. The xamComboEditor (Input) is being planned for retirement over the next few years and will not receive any new features.
And now to your question:
Both, the Infragistics.Windows.Editors.XamComboEditor and the derived Infragistics.Windows.Ribbon.ComboEditorTool, have a property for setting a default text for null values. This property is called:
NullText
The text to display when the value of the editor is null and the editor is not in edit mode. The default value is empty string. (Inherited from Infragistics.Windows.Editors.TextEditorBase)
Also the Infragistics.Controls.Editors.XamComboEditor provides such a property. It is called:
EmptyText
Gets/Sets the Text that should be displayed when the editor doesn't have anything selected. (Inherited from Infragistics.Controls.Editors.ComboEditorBase)
Example for ComboEditorTool:
Referencing the following dlls:
InfragisticsWPF4.Editors.v18.1
InfragisticsWPF4.Ribbon.v18.1
InfragisticsWPF4.v18.1
xaml-Snippet:
xmlns:ribbon="http://infragistics.com/Ribbon"
...
<ribbon:ComboEditorTool Id="SampleComboEditorTool"
NullText="Select ..."
ItemsSource="{Binding }"
/>
Screenshot:
Example for Infragistics.Windows.Editors.XamComboEditor:
Referencing the following dlls:
InfragisticsWPF4.Editors.v18.1
InfragisticsWPF4.v18.1
xaml-Snippet:
xmlns:editors="http://infragistics.com/Editors"
...
<editors:XamComboEditor Width="120" Height="23"
ItemsSource="{Binding}"
NullText="Select ..."
/>
Screenshot:
Example for Infragistics.Controls.Editors.XamComboEditor:
Referencing the following dlls:
InfragisticsWPF4.Controls.Editors.XamComboEditor.v18.1
InfragisticsWPF4.v18.1
xaml-Snippet:
xmlns:ig="http://schemas.infragistics.com/xaml"
...
<ig:XamComboEditor Width="120" Height="23"
ItemsSource="{Binding}"
EmptyText="Select ..."
/>
Screenshot:
Second side note: the first occurrence I've found for the property NullText was in the Help Doc of Version 2012.1. See here