How can I set ComboboxItem isEnable property with binding? - c#

I have a model view and a property called isEnable and I would like to set the comboboxItem IsEnable property with binding to property created in the model view , the problem is that I have datatemplate created inside a combobox , so it's not a simple Combobox , this is my code:
<ComboBox x:Name="ComboBoxUsers" ItemsSource="{Binding Users}" FontFamily="Arial" FontSize="11" Grid.Row="3" Height="30" Margin="10,5,5,5">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" >
<Image />
<TextBlock />
</StackPanel>
<DataTemplate.Resources>
<Style TargetType="ComboBoxItem">
<Setter Property="IsEnable" Value="{Binding IsEnable}"/>
</Style>
</DataTemplate.Resources>
</DataTemplate>
</ComboBox.ItemTemplate>
Simple Class of Users:
public class Users
{
public string Name { get; set; }
public bool IsEnable { get; set; }
public Users()
{
}
}
How can I achieve that?

I solved my problem by adding this code :
<ComboBox.ItemContainerStyle>
<Style TargetType="ComboBoxItem"
<Setter Property="IsEnable" Value="{Binding IsEnable}" />
</Style>
</ComboBox.ItemContainerStyle>
So the complete code will be :
<ComboBox x:Name="ComboBoxUsers" ItemsSource="{Binding Users}" FontFamily="Arial" FontSize="11" Grid.Row="3" Height="30" Margin="10,5,5,5">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" >
<Image />
<TextBlock />
</StackPanel>
<ComboBox.ItemContainerStyle>
<Style TargetType="ComboBoxItem" >
<Setter Property="IsEnable" Value="{Binding IsEnable}" />
</Style>
</ComboBox.ItemContainerStyle>
</DataTemplate>
</ComboBox.ItemTemplate>

Related

WPF binding to UserControl from Page

I have a UWP application, and it has a page containing a few textbox controls bound to A.B.C[2].D, A.B.C[2].E, A.B.C[2].F, and so on
Now I want to move the text boxes to a separate UserControl to simplify my page's XAML but
still want them to be bound to A.B.C[2].D, A.B.C[2].E etc.
How can I achieve this?
Thank you
Here is my UserControl
<UserControl
x:Class="Inspecto.HWStatusDisplayControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Truphase360"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="250">
<Grid>
<Grid.Resources>
<Style x:Key="styleTxtBox" TargetType="TextBox">
<Setter Property="IsReadOnly" Value="True" />
<Setter Property="Width" Value="75"/>
</Style>
<Style x:Key="styleTxtBlk" TargetType="TextBlock">
<Setter Property="FontSize" Value="12" />
<Setter Property="Margin" Value="10"/>
<Setter Property="Width" Value="75" />
</Style>
</Grid.Resources>
<StackPanel Orientation="Vertical" Margin="20">
<TextBlock Text="{x:Bind Header}" FontSize="16" FontWeight="Bold" Margin="10">
</TextBlock>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Temp1" Style="{StaticResource styleTxtBlk}" />
<TextBox Style="{StaticResource styleTxtBox}" Text="{Binding Mode=OneWay, Path=Temperature1 }" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Temp2" Style="{StaticResource styleTxtBlk}" />
<TextBox Style="{StaticResource styleTxtBox}" Text="{Binding Mode=OneWay, Path=Temperature2 }" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="SW Version" Style="{StaticResource styleTxtBlk}" />
<TextBox Style="{StaticResource styleTxtBox}" Text="{Binding Mode=OneWay, Path=SWVersionStr }" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="HW Version" Style="{StaticResource styleTxtBlk}" />
<TextBox Style="{StaticResource styleTxtBox}" Text="{Binding Mode=OneWay, Path=HWVersionStr }" />
</StackPanel>
</StackPanel>
</Grid>
</UserControl>
The code block directly under exists inside a page and is repeated multiple times.
The TextBoxs' were bound to {x:Bind ViewModel.DeviceData.Status.Devices[0].Temperature1 } and so on inside the Page
Now I want to display the same from UserControl.
In the data object, the instance of Devices[] is replaced every few seconds. The new array was created by deserializing from JSON object and directly assigned to like
ViewModel.DeviceData.Status.Devices = FromJSON(string);
Thank you
I agree with #EldHasp. The solution for your scenario is that you might need to create a custom dependency property in the UserControl. Then pass the A.B.C object to this property of the UserControl via binding.
I've made a simple demo about this, you could take look at the code and adjust it for your scenario.
UserControl XAML
<Grid x:Name="MyGrid">
<Grid.Resources>
<Style x:Key="styleTxtBox" TargetType="TextBox">
<Setter Property="IsReadOnly" Value="True" />
<Setter Property="Width" Value="75"/>
</Style>
<Style x:Key="styleTxtBlk" TargetType="TextBlock">
<Setter Property="FontSize" Value="12" />
<Setter Property="Margin" Value="10"/>
<Setter Property="Width" Value="75" />
</Style>
</Grid.Resources>
<StackPanel Orientation="Vertical" Margin="20">
<TextBlock Text="{x:Bind Header}" FontSize="16" FontWeight="Bold" Margin="10">
</TextBlock>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Temp1" Style="{StaticResource styleTxtBlk}" />
<TextBox Style="{StaticResource styleTxtBox}" Text="{Binding MyDependencyProperty._List[0].Name}" />
</StackPanel>
</StackPanel>
</Grid>
UserControl Code
public AClass MyDependencyProperty
{
get { return (AClass)GetValue(MyDependencyPropertyProperty); }
set { SetValue(MyDependencyPropertyProperty, value); }
}
// Using a DependencyProperty as the backing store for MyDependencyProperty. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MyDependencyPropertyProperty =
DependencyProperty.Register("MyDependencyProperty", typeof(AClass), typeof(TestUserControl), new PropertyMetadata(null));
public string Header = "TestHeader";
public TestUserControl()
{
this.InitializeComponent();
this.DataContext = this;
}
MainPage Xaml
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Foreground="Red" Text="{x:Bind ViewModel._AClass._List[1].Name}"/>
<local:TestUserControl Grid.Row="1" MyDependencyProperty="{x:Bind ViewModel._AClass}"/>
</Grid>
MainPage Code
public sealed partial class MainPage : Page
{
public TestViewModel ViewModel { get; set; }
public MainPage()
{
this.InitializeComponent();
ViewModel= new TestViewModel();
}
}
public class TestViewModel
{
public AClass _AClass { get; set; }
public TestViewModel()
{
_AClass = new AClass();
}
}
public class AClass
{
public List<BClass> _List { get; set; }
public AClass()
{
_List = new List<BClass>();
_List.Add(new BClass { Name = "123" });
_List.Add(new BClass { Name = "234" });
}
}
public class BClass
{
public string Name { get; set; }
}
And the result:

WPF ComboBox bound with object list and display less different value in selected item than in the item list

I have this ComboBox:
<ComboBox
ItemsSource="{Binding imageFormats}">
<ComboBox.ItemTemplate>
<DataTemplate>
<DockPanel>
<TextBlock DockPanel.Dock="Left" Text="{Binding Extension}" />
<TextBlock DockPanel.Dock="Left" Text=" - " />
<TextBlock DockPanel.Dock="Right" Text="{Binding Description}" />
</DockPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Which is bound to this list:
private List<ImageFormatModel> imageFormats = new List<ImageFormatModel>();
public MainWindow()
{
ComboBoxImages.ItemsSource = imageFormats;
}
The Object ImageFormatModel consists of two strings:
public class ImageFormatModel
{
public string Extension { get; set; }
public string Description { get; set; }
}
Is possible that the selected item shows only the extension but in the dropdown menu both are shown?
Both values should be shown in this menu:
But if I select one, only the extension should be visible. Not like this:
You could apply a Style with a DataTrigger to the TextBlock elements to be hidden:
<DataTemplate>
<DockPanel>
<DockPanel.Resources>
<Style x:Key="tbStyle" TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=ComboBoxItem}}" Value="{x:Null}">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DockPanel.Resources>
<TextBlock DockPanel.Dock="Left" Text="{Binding Extension}" />
<TextBlock DockPanel.Dock="Left" Text=" - " Style="{StaticResource tbStyle}" />
<TextBlock DockPanel.Dock="Right" Text="{Binding Description}" Style="{StaticResource tbStyle}" />
</DockPanel>
</DataTemplate>

Binding two XAML element properties to the same ViewModel property does not work

Problem description
I use the Master Details View control. It has two properties Details Header and SelectedItem. I bind both to the Selected property in ViewModel. The goal is to change the DetailsHeader header depending on the selected item. The problem is that only SelectedItem is updated. The text does not appear in the DetailsHeader.
DetailsHeader="{x:Bind ViewModel.Selected, Mode=OneWay}"
SelectedItem="{x:Bind ViewModel.Selected, Mode=OneWay}"
If link one to the other, it works correctly - both are updated.
DetailsHeader="{x:Bind masterDetailsView.SelectedItem, Mode=OneWay}"
SelectedItem="{x:Bind ViewModel.Selected, Mode=OneWay}"
I do not find in the documentation a restriction on the fact that a property from a context can only be bound to one property of a XAML element. What could be the problem?
Code
ViewModelBase from MVVM Light is used for notification of changes. Its Set() method updates the property and raises a change event.
private SampleVendorModel _selected;
public SampleVendorModel Selected
{
get => _selected;
set => Set(ref _selected, value);
}
Model
public class SampleVendorModel
{
public string Name { get; set; }
public string Surname { get; set; }
public string MiddleName { get; set; }
public string FullName => $"{Surname} {Name} {MiddleName}";
public string NameWithoutSurname => $"{Name} {MiddleName}";
}
MasterDetailsView
<controls:MasterDetailsView Name="masterDetailsView"
MasterHeader="{x:Bind ViewModel.Title}"
MasterHeaderTemplate="{StaticResource MasterHeaderTemplate}"
DetailsHeader="{x:Bind masterDetailsView.SelectedItem, Mode=OneWay}"
DetailsHeaderTemplate="{StaticResource DetailsHeaderTemplate}"
ItemsSource="{x:Bind ViewModel.Items, Mode=OneWay}"
SelectedItem="{x:Bind ViewModel.Selected, Mode=OneWay}"
ItemTemplate="{StaticResource ItemTemplate}"
DetailsTemplate="{StaticResource DetailsTemplate}"
BorderBrush="Transparent"
BackButtonBehavior="Manual">
</controls:MasterDetailsView>
Resource's page
<Page.Resources>
<Style x:Key="HeaderStyle" TargetType="TextBlock">
<Setter Property="FontSize" Value="30" />
<Setter Property="FontWeight" Value="Light" />
<Setter Property="Margin" Value="0, 10, 0, 10" />
<Setter Property="TextTrimming" Value="CharacterEllipsis"/>
</Style>
<DataTemplate x:Key="MasterHeaderTemplate">
<TextBlock Text="{Binding}" Style="{StaticResource HeaderStyle}"/>
</DataTemplate>
<DataTemplate x:Key="DetailsHeaderTemplate" x:DataType="viewmodels:SampleVendorModel">
<TextBlock Text="{x:Bind FullName}" Style="{StaticResource HeaderStyle}" />
</DataTemplate>
<DataTemplate x:Key="ItemTemplate" x:DataType="viewmodels:SampleVendorModel">
<Grid Margin="0, 10, 0, 10" RowSpacing="2">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="{x:Bind Surname}" FontWeight="Bold" FontSize="16" TextTrimming="CharacterEllipsis" />
<TextBlock Grid.Row="1" Text="{x:Bind NameWithoutSurname}" TextTrimming="CharacterEllipsis" />
</Grid>
</DataTemplate>
<DataTemplate x:Key="DetailsTemplate"
x:DataType="viewmodels:SampleVendorModel">
<StackPanel Margin="10">
<TextBlock Text="{x:Bind Surname}" />
<TextBlock Text="{x:Bind Name}" />
<TextBlock Text="{x:Bind MiddleName}" />
</StackPanel>
</DataTemplate>
</Page.Resources>
The problem is that only SelectedItem is updated
I wronged. MasterDetailsView.SelectedItem is updated via property ViewModel.Selected in the code. In case UI navigation, ViewModel.Selected doesn't change. Because binding mode is OneWay. As a consequence, MasterDetailsView.DetailsHeader doesn't get notify about change selected.
In order to solve the problem, need to set mode as TwoWay for MasterDetailsView.SelectedItem.
DetailsHeader="{x:Bind ViewModel.Selected, Mode=OneWay}"
SelectedItem="{x:Bind ViewModel.Selected, Mode=TwoWay}"

How to make TextBlock Text Selectable on a WPF DataGrid Group Header or Anyother way to do it

I am working on displaying rows which are grouped on WPF DataGrid
Group Header which I am currently displaying is a TextBlock, and the text displayed on the TextBlock is not selectable.
How can I make TextBlock text selectable so that I can copy the value.
Following is the XAML.
I am using following code to Bind data to the grid and group the data.
Entity:
public class AverageCounter
{
public string CounterName { get; set; }
public string Role { get; set; }
public string RoleInstance { get; set; }
public decimal CounterAverageValue { get; set; }
}
Code to Bind and Group.
var results = new ListCollectionView(queryResultSet);
if (results.GroupDescriptions != null)
{
results.GroupDescriptions.Add(new PropertyGroupDescription("CounterName"));
}
dataGrid1.AutoGenerateColumns = true;
dataGrid1.ItemsSource = results;
XAML:
<Window x:Class="CheckPerfromanceCounters.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:CheckPerfromanceCounters"
Title="MainWindow" Height="390" Width="878">
<Window.Resources>
<local:AvgConverter x:Key="avgConverter"/>
</Window.Resources>
<Grid>
<Button Content="Refresh" Height="23" HorizontalAlignment="Left" Margin="769,328,0,0" Name="button1"
VerticalAlignment="Top" Width="75" Click="Button1Click" />
<DataGrid AutoGenerateColumns="True" Height="310" HorizontalAlignment="Left" Margin="12,12,0,0"
Name="dataGrid1" VerticalAlignment="Top" Width="832">
<DataGrid.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=CounterName}" />
</StackPanel>
</DataTemplate>
</GroupStyle.HeaderTemplate>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander>
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Name}" FontStyle="Italic"/>
<TextBlock><Bold> - Average: </Bold></TextBlock>
<TextBlock Text="{Binding Converter={StaticResource avgConverter}}" />
</StackPanel>
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</DataGrid.GroupStyle>
</DataGrid>
</Grid>
</Window>
if you need anyother information please let me know.
Just use TextBox and make it readonly, then you can change the TextBox.Style to make it looks like TextBlock.
Perhaps something like this
<TextBox IsReadOnly="True"
BorderThickness="0"
Background="Transparent"
TextWrapping="Wrap" />
Use TextBox with IsReadOnly ="True" but also set the binding mode to oneWay :
Text="{Binding Converter={StaticResource avgConverter}, Mode=OneWay}"

How to display a control dynamically in wpf?

I have a collection with fields cityname, statename and countryname and I bind that collection to my wpf form. I want to display the cityname in a Textbox, the statename in a combobox and the countryname in a combobox. All the textboxes and comboboxes should come dynamically. How can I do this job?
Any one suggest me how to design this form dynamically in wpf using MVVM
I am trying to do this code but not get result properly
<UserControl.Resources>
<DataTemplate x:Key="IntegerTemplate">
<DockPanel>
<TextBox Margin="10,0,0,0" x:Name="IntegerTemplate" Grid.Column="1" MaxLength="{Binding Path=CardField.MaximumLength}" Text="{Binding Path=CardField.FieldData, Mode=TwoWay}" />
</DockPanel>
</DataTemplate>
<DataTemplate x:Key="StringTemplate">
<DockPanel>
<ComboBox Margin="10,0,0,0" x:Name="cmbFieldData" Grid.Column="1" Text="{Binding Path=CardField.FieldData, Mode=TwoWay}" />
</DockPanel>
</DataTemplate>
<DataTemplate x:Key="DefaultTemplate">
</DataTemplate>
<DataTemplate x:Key="dataTemplate">
<ContentControl x:Name="MyContentControl" Content="{Binding}" ContentTemplate="{StaticResource DefaultTemplate}"/>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=CardField.FieldTag}" Value="City">
<Setter TargetName="MyContentControl" Property="ContentTemplate"
Value="{StaticResource IntegerTemplate}" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=CardField.FieldTag}" Value="State">
<Setter TargetName="MyContentControl" Property="ContentTemplate"
Value="{StaticResource StringTemplate}" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=CardField.FieldTag}" Value="Country">
<Setter TargetName="MyContentControl" Property="ContentTemplate"
Value="{StaticResource StringTemplate}" />
</DataTrigger>
<!-- and so on -->
</DataTemplate.Triggers>
</DataTemplate>
</UserControl.Resources>
we are using this code in our xaml page
<ItemsControl x:Name="items"
ItemsSource="{Binding}"
ItemTemplate="{StaticResource dataTemplate}"
/>
UPDATE:
i am trying to do this following code:
<TextBlock x:Name="tbFieldTag" Cursor="Hand" VerticalAlignment="Center" HorizontalAlignment="Stretch" TextWrapping="Wrap" Margin="10,0,0,0" Text="{Binding Path=CardField.FieldTag}" />
<ItemsControl x:Name="items"
ItemsSource="{Binding}"
ItemTemplate="{StaticResource dataTemplate}"/>
In that i got Value of TextBlock but i am not getting the value in ItemTemplate. so where I doing wrong?
Try this:
1) data template selector
public class CardFieldTemplateSelector : IValueConverter
{
public DataTemplate CityNameTemplate { get; set; }
public DataTemplate StateNameTemplate { get; set; }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
string fieldTag = (string) value;
switch (fieldTag)
{
case "City":
return CityNameTemplate;
case "State":
return StateNameTemplate;
}
throw new ArgumentOutOfRangeException();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
2) XAML:
<selectors:CardFieldTemplateSelector x:Key="cardFieldTemplateSelector">
<selectors:CardFieldTemplateSelector.CityNameTemplate>
<DataTemplate>
<DockPanel>
<TextBox Margin="10,0,0,0" x:Name="IntegerTemplate" Grid.Column="1" MaxLength="{Binding Path=CardField.MaximumLength}" Text="{Binding Path=CardField.FieldData, Mode=TwoWay}" />
</DockPanel>
</DataTemplate>
</selectors:CardFieldTemplateSelector.CityNameTemplate>
<selectors:CardFieldTemplateSelector.StateNameTemplate>
<DataTemplate>
<DockPanel>
<ComboBox Margin="10,0,0,0" x:Name="cmbFieldData" Grid.Column="1" Text="{Binding Path=CardField.FieldData, Mode=TwoWay}" />
</DockPanel>
</DataTemplate>
</selectors:CardFieldTemplateSelector.StateNameTemplate>
</selectors:CardFieldTemplateSelector>
<DataTemplate x:Key="dataTemplate">
<ContentControl x:Name="MyContentControl"
Content="{Binding}"
ContentTemplate="{Binding CardField.FieldTag, Converter={StaticResource cardFieldTemplateSelector}"/>
</DataTemplate>
<ItemsControl x:Name="items"
ItemsSource="{Binding}"
ItemTemplate="{StaticResource dataTemplate}"/>
Why can;t you use the WPF Data Form from Codeplex.
You can add custom editors in this form, based on the data types.
Hope this help.

Categories

Resources