I am wondering if anyone could explain me the difference between
binding a selected value of a Collection to a comboBox.
Or Binding the value to a Button Content.
Like that
<ComboBox x:Name="_culturedTitleViewModelSelector" Visibility="Hidden" Style="{StaticResource ResourceKey=_culturedTitleViewModelSelectorStyle}"
ItemsSource="{Binding Path=AvailableCultures, Source={x:Static Localized:ResourcesManager.Current}}"
SelectedValue="{Binding Path=CurrentCulture, Source={x:Static Localized:ResourcesManager.Current}}"
<Button x:Name="LanguageBtn" Content="{Binding Path=CurrentCulture, Source={x:StaticLocalized:ResourcesManager.Current}}"
The issue is If i Don't use the ComboBox up there, the DependencyProperty I Have in another class is not being called.
But if I Use the comboBox everything works...
Altought the comboBox doesnt do anything it's just a "workarround"
In my CS code when i CLick on my button I DO that :
ResourcesManager.Current.SwitchToNextCulture();
//We use a dummy comboBox to make sure the LanguageBehavior Property is being notified.
_culturedTitleViewModelSelector.SelectedItem = ResourcesManager.Current.CurrentCulture;
And if I Dont set the SelectedItem of the combobox to another culture. My languageBehavior class is not notified.
:
public class LanguageBehavior
{
public static DependencyProperty LanguageProperty =
DependencyProperty.RegisterAttached("Language",
typeof(string),
typeof(LanguageBehavior),
new UIPropertyMetadata(OnLanguageChanged));
public static void SetLanguage(FrameworkElement target, string value)
{
target.SetValue(LanguageProperty, value);
}
public static string GetLanguage(FrameworkElement target)
{
return (string)target.GetValue(LanguageProperty);
}
private static void OnLanguageChanged(DependencyObject target, DependencyPropertyChangedEventArgs e)
{
var element = target as FrameworkElement;
if (e.NewValue!=null)
element.Language = XmlLanguage.GetLanguage(e.NewValue.ToString());
}
}
I'd expect ComboBox Content to work the same as Button Content.
In my Generic.Xaml i do that :
<Style TargetType="{x:Type TextBlock}" x:Key="_textBlockLanguageProperty">
<Setter Property="WpfServices:LanguageBehavior.Language" Value="{Binding Path=CurrentCulture, Source={x:Static Localized:ResourcesManager.Current}}"
/>
</Style>
And that is CurrentCulture
public CultureInfo CurrentCulture
{
get { return CultureProvider.Current; }
set
{
if (value != CultureProvider.Current)
{
CultureProvider.Current = value;
OnCultureChanged();
}
}
}
Current :
public static ResourcesManager Current
{
get
{
if (_resourcesManager == null)
{
var cultureProvider = new BaseCultureProvider();
_resourcesManager = new ResourcesManager(cultureProvider);
_resourcesManager.Init();
}
return _resourcesManager;
}
}
EDIT :
My _culturedTitelViewModelSelectorStyle is
<Style TargetType="{x:Type ComboBox}" x:Key="_culturedTitleViewModelSelectorStyle">
<Setter Property="DisplayMemberPath" Value="DisplayName" />
<Setter Property="SelectedValuePath" Value="." />
<Setter Property="HorizontalAlignment" Value="Right" />
<Setter Property="MaxHeight" Value="40" />
<Setter Property="FontSize" Value="20" />
<Setter Property="Margin" Value="5" />
<Setter Property="SelectedIndex" Value="0" />
<Setter Property="IsSynchronizedWithCurrentItem" Value="True" />
</Style>
In the ComboBox you are binding the SelectedValue to a specific culture. This will select that culture from the list of available cultures, and therefor, trigger a set on the CurrentCulture property.
The Content property of a Button is merely displaying something to the user, it is not doing any assigning. It reads the property value and then displays it. That is why you need to manually change the Culture in the Click event to get it to do anything.
If you want the user to be able to select a value from a list of available values, a ComboBox or ListBox is the way to go. A Button is for triggering a specific action, not for selecting from a list.
Related
I am getting my buttons to appear, but their styling is not displaying and i'm not sure why.
Below is the XAML code and how it is defined in the view model.
private ObservableCollection<Button> myButtons;
public ObservableCollection<Button> MyButtons
{
get { return myButtons; }
set
{
if (myButtons == null)
{
myButtons = value; OnPropertyChanged("MyButtons");
}
}
}
private void PopulateButtons()
{
List<Button> buttonsToAdd = new List<Button>();
List<string> buttonsToAdd = new List<string>();
foreach (var item in SettingsSingleton.RowColumnOptions)
{
int total = item.Key;
Tuple<int, int> rowColumn = item.Value;
buttonsToAdd.Add((total).ToString());
}
MyButtons = new ObservableCollection<Button>(buttonsToAdd);
}
And XAML is
<StackPanel DockPanel.Dock="Top"
HorizontalAlignment="Center" VerticalAlignment="Center">
<ItemsControl ItemsSource="{Binding MyButtons}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Command="{Binding Create_Click}" CommandParameter="{Binding Content}">
<Button.Style>
<Style TargetType="Button" BasedOn="{StaticResource NiceStyleButton}">
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Margin" Value="20"/>
<Setter Property="Padding" Value="6"/>
<Setter Property="FontSize" Value="42"/>
</Style>
</Button.Style>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
I also get a weird warning/error:
System.Windows.Data Error: 26 : ItemTemplate and ItemTemplateSelector are ignored for items already of the ItemsControl's container type; Type='Button'
Can anyone help? Thank you.
EDIT:
My Create_Click command and the functions that then get called by it.
private ICommand createClickCommand;
public ICommand Create_Click
{
get
{
if (createClickCommand == null)
{
createClickCommand = new RelayCommand(CreateGrid);
}
return createClickCommand;
}
}
private void CreateGrid(object param)
{
Generate(param);
}
And RowColumnOptions is basically just a tuple of int, int, where we define a row and column. This is used for the Grid creation. This is where RowColumnOptions gets populated.
public static class SystemSettingsSingleton
{
public static Dictionary<int, Tuple<int, int>> RowColumnOptions = new Dictionary<int, Tuple<int, int>>();
public static void SetOptions(List<string> Options)
{
// Let's parse our options
foreach (var option in Options)
{
var rowAndColumnSettings = option.Split('x');
// Check that we have both row and column count
int rowCount, columnCount = 0;
if (rowAndColumnSettings.Length == 2 && int.TryParse(rowAndColumnSettings[0], out rowCount)
&& int.TryParse(rowAndColumnSettings[1], out columnCount))
{
RowColumnOptions.Add( (rowCount * columnCount),
new Tuple<int, int>(rowCount, columnCount) );
}
}
}
}
That SetOptions method is coming from a static class.
You shouldn't have an observable collection of Button. That's never a good idea. It's telling you it's ignoring the ItemTemplate because you are giving it controls in the collection, which is unnecessary. Then you're trying to create another button in the item template. Templates in WPF don't mean what you think they do: They don't style content, they create content. Don't create buttons in your viewmodel, create them in your item template. Your ObservableCollection should just provide the information the item template will need to create the buttons you want to see. Here, that's just one string.
But it turns out that your options really consist of tuples. You want to display their products in the button content, and you want to pass the tuples themselves as the command parameter. This is easy.
public class ViewModel : ViewModelBase
{
public Dictionary<int, Tuple<int, int>> RowColumnOptions
=> SystemSettingsSingleton.RowColumnOptions;
private void PopulateButtons()
{
OnPropertyChanged(nameof(RowColumnOptions));
}
// I don't know what your relay command class looks like, I just tossed one
// together that has an Action<object>
public ICommand Create_Click { get; } = new RelayCommand(param =>
{
var tuple = param as Tuple<int, int>;
MessageBox.Show($"Parameter: {tuple.Item1} x {tuple.Item2}");
});
}
And the ItemsControl:
<ItemsControl ItemsSource="{Binding RowColumnOptions}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<!--
The DataContext here is a KeyValuePair<int, Tuple<int, int>>
The product of x * y was the Key, so that's what we'll display in the button's
Content.
We could display all three values if we wanted to.
We want to pass the tuple to the command, and that's the Value of the KeyValuePair.
So we bind that to CommandParameter
-->
<Button
Command="{Binding DataContext.Create_Click, RelativeSource={RelativeSource AncestorType=ItemsControl}}"
CommandParameter="{Binding Value}"
Content="{Binding Key}"
>
<Button.Style>
<Style TargetType="Button" BasedOn="{StaticResource NiceStyleButton}">
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Margin" Value="20"/>
<Setter Property="Padding" Value="6"/>
<Setter Property="FontSize" Value="42"/>
</Style>
</Button.Style>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Some questions linger in my mind: What if you have both "2x6" and "3x4" in that initial list of options? The first one that comes in will be replaced by the second. Is that the desired behavior?
In WPF Arabic Mode (FlowDirection="RightToLeft").
When i give a number like -24.7% it will print this as %24.7-
Following code will fix the above mentioned issues.
<Window.Resources>
<Style TargetType="Run">
<Setter Property="FlowDirection" Value="LeftToRight" />
</Style>
</Window.Resources>
<Grid FlowDirection="RightToLeft" >
<Grid HorizontalAlignment="Left" Margin="114,127,0,0" VerticalAlignment="Top" Width="279" Height="97">
<TextBlock x:Name="textBlock" Text="-24.7%" ><Run></Run></TextBlock>
</Grid>
</Grid>
Now i want to put the <run><run> tag to all of my Text Blocks Contents, How can i achieve this, So i don't have to replace all of my TextBlocks in the code.
How to do this by creating a Style...??
note: I can't go to the TextAlign=Right solution as i can't edit all the textblockes in the application
Can't say I like your approach, but I don't know Arabic gotchas and your situation, so won't argue about that. You can achieve what you want using attached properties (or blend behaviors). Like this:
public static class StrangeAttachedProperty {
public static bool GetAddRunByDefault(DependencyObject obj) {
return (bool) obj.GetValue(AddRunByDefaultProperty);
}
public static void SetAddRunByDefault(DependencyObject obj, bool value) {
obj.SetValue(AddRunByDefaultProperty, value);
}
public static readonly DependencyProperty AddRunByDefaultProperty =
DependencyProperty.RegisterAttached("AddRunByDefault", typeof (bool), typeof (StrangeAttachedProperty), new PropertyMetadata(AddRunByDefaultChanged));
private static void AddRunByDefaultChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
var element = d as TextBlock;
if (element != null) {
// here is the main point - you can do whatever with your textblock here
// for example you can check some conditions and not add runs in some cases
element.Inlines.Add(new Run());
}
}
}
And in your resources set this property for all text blocks:
<Window.Resources>
<Style TargetType="TextBlock">
<Setter Property="local:StrangeAttachedProperty.AddRunByDefault" Value="True" />
</Style>
<Style TargetType="Run">
<Setter Property="FlowDirection" Value="LeftToRight" />
</Style>
</Window.Resources>
I have a DevExpress Grid Control. I want to enable/disable a button based on the selected rows in the grid control, i.e., if any rows are selected in the grid control then this button should be enabled. Following is my GridControl code:
<dxg:GridControl x:Name="gridFloorplans" Grid.Column="1" Grid.Row="1" AutoGenerateColumns="None"
ItemsSource="{Binding FloorplanList.Result.View}"
SelectedItems="{Binding SelectedFloorplan,Mode=TwoWay}"
dx:ThemeManager.Theme="Default" SelectionMode="Row">
<dxg:GridControl.View>
<dxg:TableView AllowGrouping="False" ShowGroupPanel="False" AllowEditing="False" ShowDataNavigator="True" DataNavigatorButtons="Navigation" />
</dxg:GridControl.View>
<dxg:GridControl.Columns>
<dxg:GridColumn FieldName="Name" Header="Floorplan Name" Fixed="Left" />
<dxg:GridColumn FieldName="Season" Fixed="Left" />
<dxg:GridColumn FieldName="Version" Fixed="Left" />
</dxg:GridControl.Columns>
</dxg:GridControl>
Following is my ViewModel code:
private ObservableCollection<FloorplanData> _selectedFloorplan;
public FloorplanSearchViewModel(IErrorHandlerService inErrorHandler, INavigationService inNavigationService,
ISpaDataAdapter inDataAdapter, IAuthorizationService inAuthService)
{
// Set the commands
this.ShowStoreSetCommand = new DelegateCommand<IList<object>>(this.ShowStoreSet, this.CanShowStoreSet);
this.SearchFloorplansCommand = new DelegateCommand(this.SearchFloorplans);
this.ShowStatusChangeCommand = new DelegateCommand<IList<object>>(this.ShowStatusChange, this.CanShowStatusChange);
// Set up the default values for the search
this.StatusList = new List<object>();
this.StatusList.Add(Enum.GetName(typeof(FloorplanData.FloorplanStatus), FloorplanData.FloorplanStatus.Pending));
this.StatusList.Add(Enum.GetName(typeof(FloorplanData.FloorplanStatus), FloorplanData.FloorplanStatus.Review));
//Initiate the SelectedFloorplan property
//SelectedFloorplan = new ObservableCollection<FloorplanData>();
}
public ObservableCollection<FloorplanData> SelectedFloorplan
{
get
{
return _selectedFloorplan;
}
set
{
_selectedFloorplan = value;
this.ShowStatusChangeCommand.RaiseCanExecuteChanged();
}
}
public NotifyTaskCompletion<CollectionViewSource> FloorplanList
{
get;
private set;
}
private void ShowStatusChange(IList<object> inFloorplans)
{
try
{
// Create the navigation output
NavigationParameters args = new NavigationParameters();
args.Add(FloorplanStatusChangeViewModel.PARAM_FLOORPLAN_ID_LIST, GetFloorplanIdList(inFloorplans));
_navigationService.NavigateTo<Views.FloorplanStatusChangeView>(args);
}
catch (Exception ex)
{
_errorHandler.HandleError(ex);
}
}
private bool CanShowStatusChange(IList<object> inFloorplans)
{
// Check security to see if the current user is allowed to enter the status change screen
if (_authService.GetAccessLevel(1470) > AuthorizationLevel.None)
{
if (SelectedFloorplan!=null)
return true;
else
return false;
}
else
{
return false;
}
}
Following is the xaml code for the button:
<Button Margin="4,2" Content="Status Change" Command="{Binding ShowStatusChangeCommand}"
CommandParameter="{Binding SelectedItems, ElementName=gridFloorplans}">
<Button.Style>
<Style TargetType="Button">
<Setter Property="ToolTip" Value="Open the Floorplan Status Change view for the selected floorplans" />
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="ToolTip" Value="You do not have access to open the Floorplan Status Change view" />
</Trigger>
<DataTrigger
Binding ="{Binding ElementName=gridFloorplans, Path=SelectedFloorplan}"
Value="-1">
<Setter Property="Button.IsEnabled" Value="false"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
How can I enable/disable ShowStatus button based on whether any row is selected in the grid or not?
//You are not using `inFloorplans` parameter within your method body
//Need not pass this parameter
private bool CanShowStatusChange(IList<object> inFloorplans)
Same as CanShowStatusChange method create a property and bind it to the Button which you want to enable/disable
public bool CanShowStatusChange
{
get
{
if (_authService.GetAccessLevel(1470) > AuthorizationLevel.None)
{
if (SelectedFloorplan!=null)
return true;
else
return false;
}
else
{
return false;
}
}
}
Selected floor plan cant be an observable collection. The name detotes its a It denotes a single object. So
private FloorplanData _selectedFloorplan;
public FloorplanData SelectedFloorplan
{
get
{
return _selectedFloorplan;
}
set
{
_selectedFloorplan = value;
NotifyPropertyChanged("SelectedFloorplan");
//or its equivalent method to notify the change
NotifyPropertyChanged("CanShowStatusChange");
//or its equivalent method to notify the change of CanShowStatusChange.
}
}
Make sure you bind SelectedFloorplan property and CanShowStatusChange property in your UI so that they are updated.
1) IsEnabled will get bool value from CanShowStatusChange, so you dont need style.
2) You have grid`s selected items in VM, so why pass it via parameter?
<Button Margin="4,2" Content="Status Change" Command="{Binding ShowStatusChangeCommand}">
<Button.Style>
<Style TargetType="Button">
<Setter Property="ToolTip" Value="Open the Floorplan Status Change view for the selected floorplans" />
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="ToolTip" Value="You do not have access to open the Floorplan Status Change view" />
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
3) You set SelectedFloorplan ones, then you just change items in collection! It means than we should subscribe on CollectionChanged
public FloorplanSearchViewModel(IErrorHandlerService inErrorHandler, INavigationService inNavigationService,
ISpaDataAdapter inDataAdapter, IAuthorizationService inAuthService)
{
// Set the commands
this.ShowStoreSetCommand = new DelegateCommand<IList<object>>(this.ShowStoreSet, this.CanShowStoreSet);
this.SearchFloorplansCommand = new DelegateCommand(this.SearchFloorplans);
this.ShowStatusChangeCommand = new DelegateCommand<IList<object>>(this.ShowStatusChange, this.CanShowStatusChange);
// Set up the default values for the search
this.StatusList = new List<object>();
this.StatusList.Add(Enum.GetName(typeof(FloorplanData.FloorplanStatus), FloorplanData.FloorplanStatus.Pending));
this.StatusList.Add(Enum.GetName(typeof(FloorplanData.FloorplanStatus), FloorplanData.FloorplanStatus.Review));
//Initiate the SelectedFloorplan property
SelectedFloorplan = new ObservableCollection<FloorplanData>();
SelectedFloorplan.CollectionChanged += SelectedFloorplanOnCollectionChanged;
}
private void SelectedFloorplanOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs notifyCollectionChangedEventArgs)
{
this.ShowStatusChangeCommand.RaiseCanExecuteChanged();
}
public ObservableCollection<FloorplanData> SelectedFloorplan
{
get
{
return _selectedFloorplan;
}
set
{
_selectedFloorplan = value;
this.ShowStatusChangeCommand.RaiseCanExecuteChanged();
}
}
4) And
private bool CanShowStatusChange()
{
// Check security to see if the current user is allowed to enter the status change screen
if (_authService.GetAccessLevel(1470) > AuthorizationLevel.None)
{
if (SelectedFloorplan!=null && SelectedFloorplan.Any())
return true;
else
return false;
}
else
{
return false;
}
}
I had a checkbox all column inside the datagrid in WPF C#.
<DataGridCheckBoxColumn Binding="{Binding IsSelected,UpdateSourceTrigger=PropertyChanged}" CanUserSort="False">
<DataGridCheckBoxColumn.ElementStyle>
<Style TargetType="CheckBox" BasedOn="{StaticResource {x:Type CheckBox}}">
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="HorizontalAlignment" Value="Center"/>
</Style>
</DataGridCheckBoxColumn.ElementStyle>
<DataGridCheckBoxColumn.HeaderTemplate>
<DataTemplate x:Name="dtAllChkBx">
<CheckBox Name="cbxAll" HorizontalAlignment="Center" Margin="0,0,5,0" IsEnabled="{Binding Path=DataContext.IsCbxAllEnabled,RelativeSource={RelativeSource AncestorType=DataGrid}}"
IsChecked="{Binding Path=DataContext.AllSelected,RelativeSource={RelativeSource AncestorType=DataGrid},UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</DataGridCheckBoxColumn.HeaderTemplate>
</DataGridCheckBoxColumn>
When I check the All checkbox, of course, it will mark all the checkboxes, but once I uncheck one checkbox, the All checkbox is still checked. This should be unchecked. How should I do that using WPF C#.
If I understood you correctly - after any change of IsSelected property inside collection item you should update AllSelected value.
So, you need some callback inside all your items(event or Action or any mechanism you want) and change get logic for AllSelected
Here is some draft for item IsSelected property and constructor:
public bool IsSelected {
get { return isSelected; }
set {
isSelected = value;
OnPropertyChanged();
if (globalUpdate != null) globalUpdate();
}
}
public ItemClass(Action globalUpdate, ...your parameters) {
this.globalUpdate = globalUpdate;
...do smth with your parameters
}
Example of usage:
new ItemClass(() => OnPropertyChanged("AllSelected"))
And of course don't forget about AllSelected getter
public bool AllSelected {
get { return YourGridItemsCollection.All(item => item.IsSelected); }
Now when you check manually all items then AllSelected will be automatically checked, and unchecked when you uncheck any item.
I have a simple class:
public class Foo
{
public string Text { get; set; }
public bool AppleStyle { get; set; }
public Foo(string text, bool applyStyle)
{
Text = text;
ApplyStyle = applyStyle;
}
public override string ToString()
{
return Text;
}
}
Which is then used to add items to a ListBox:
var one = new Foo("Some Text", false);
var two = new Foo("More Text", true);
MyListBox.Items.Add(one);
MyListBox.Items.Add(two);
I then loop through the items in the ListBox to figure out how to style them. This is where I get stuck. I tried inheriting from ListBoxItem for the class, but no items get added if I do that.
for (int i = 0; i < MyListBox.Items.Count; i++)
{
if(((Foo)MyListBox.Items[i]).ApplyStyle)
{
((ListBoxItem)MyListBox.Items[i]).Style = Resources["MyStyle"] as Style;
}
}
Update:
In MainWindow.xaml:
<Window.Resources>
<Style x:Key="MyStyle" TargetType="ListBoxItem">
<Setter Property="Background" Value="Bisque"></Setter>
<Setter Property="FontWeight" Value="Bold"></Setter>
</Style>
</Window.Resources>
Update 3:
Making some progress, just need to know how to refresh the styles (after clicking on a button). Plus if Resource is not in MainWindow.xaml, would it then look in App.xaml before returning null?
MainWindow.xaml
<Window...>
<Window.Resources>
<Style x:Key="MyClass" TargetType="ListBoxItem">
<Setter Property="Background" Value="Bisque"></Setter>
<Setter Property="FontWeight" Value="Bold"></Setter>
</Style>
<myapp:MyListItemStyleSelector x:Key="MyListItemStyleSelector" />
</Window.Resources>
<Grid>
...
<ListBox .... ItemContainerStyleSelector="{StaticResource: MyListItemStyleSelector}" />
...
</Grid>
</Window>
MyListItemStyleSelector.cs
public class MyListItemStyleSelector : StyleSelector
{
public override Style SelectStyle(object item, DependencyObject container)
{
ItemsControl ic = ItemsControl.ItemsControlFromItemContainer(container);
int index = ic.ItemContainerGenerator.IndexFromContainer(container);
Style applyStyle = null;
var data = item as Foo;
if (data != null && data.ApplyStyle)
{
applyStyle = ic.TryFindResource("MyStyle") as Style;
}
return applyStyle;
}
}
I think you have some sort of mixup here, i try to explain as good as i can.
First of all You usually never need to change the Style in code, like your last code block.
One thing that is difficult to understand in the beginning is the use of a ItemContainerStyle and DataTemplate.
I would suggest that you do the following.
Instead of changing the style off your ListBoxItem see if it is sufficient to use a DataTemplate. The DataTemplate defines how the Content of your ListBoxItem is shown.
<DataTemplate TargetType="{x:Type Foo}">
<!-- your visuals and controls here -->
</DataTemplate>
Now if you want to use different datatemplates you could use different classes and create different DataTemplates for them, or you use a DataTemplateSelector
public class FooTemplateSelector : DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
FrameworkElement element = container as FrameworkElement;
var mdl = item as Foo;
if( mdl.AppleStyle )
return element.FindResource("appleTemplate") as DataTemplate;
return element.FindResource("normalTemplate") as DataTemplate;
}
}
Create that templateselector in xaml and reference it in your listbox
<myNs:FooTemplateSelector x:Key="fooTemplateSelector"/>
<Listbox DataTemplateSelector="{StaticResource fooTemplateSelector}"/>
now you need to create 2 DataTemplates appleTemplate *normalTemplate* and you can easyl distinguish which data template to use vial the selector. Which is done automatically in the ListBox for you.
If you really want to change the Style of the ItemContainer you can use ItemContainerStyleSelector which works similar to the DataTemplateSelector. But i would not suggest it. You should supply the content and leave the ListBoxItem as it is, only if you want to modify the design(in this case, the selection color etc.), otherwise it might confuse the user or break functionality.
If you add data-objects directly to the ListBox the container-items will be generated automatically, you cannot get them this way.
Use the ItemContainerGenerator:
((ListBoxItem)MyListBox.ItemContainerGenerator.ContainerFromIndex(i)).Style = Resources["MyStyle"] as Style;
Why not do this in the XAML?
<ListBox Name="MyListBox">
<ListBox.Resources>
<Style TargetType="{x:Type ListBoxItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding ApplyStyle}" Value="True">
<Setter Property="Background" Value="Bisque" />
<Setter Property="FontWeight" Value="Bold" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.Resources>
</ListBox>
But your overall problem is that ListBox.Items returns a collection of data objects, not XAML Controls. To get the XAML control that contains the Data Object you have to do as H.B. suggested and use MyListBox.ItemContainerGenerator.ContainerFromItem(dataObject) to get the XAML Container for the data object. Just be sure you wait until after the ItemContainerGenerator has finished rendering items to get the container (I believe it has a Status property or StatusChanged event you can use... it's been a while and I can't remember the exact syntax)