I have been struggling with this for three days now and I feel I am very close to a solution, but I just can't get there.
I am making a sudoku puzzle and I would like to create a custom control to display one of the nine 3x3 grids, so I dan display nine of them and have a nice 9x9 grid.
I have found at least 30 different pages that should explain how to create this but I could not find the solution on each of them.
I think the problem lays in the PartialSudokuGrid because the Values property doesn't seem to get called. Also, no errors are displayed in the output window. Can anyone tell me what I am doing wrong?
Not meaning to dump code and expect someone to fix it, but I am really stuck on this and I feel as if it is just a little change that will make everything work.
Here is my code:
MainWindow:
<Window x:Class="SudokuWPF.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SudokuWPF"
Title="MainWindow" Height="400" Width="400"
DataContext="{Binding PartialSudokuGrid, Source={StaticResource Locator}}">
<UniformGrid Columns="3" Rows="3">
<local:PartialSudokuGrid Values="{Binding ValuesVM}" />
</UniformGrid>
</Window>
ViewModel:
public class PartialSudokuGridVM : ViewModelBase {
private int[] _values;
public PartialSudokuGridVM() {
this.ValuesVM = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
}
public int[] ValuesVM {
get {
return this._values;
}
set {
this._values = value;
this.RaisePropertyChanged();
}
}
}
UserControl:
<UserControl x:Class="SudokuWPF.PartialSudokuGrid"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
DataContext="{Binding RelativeSource={RelativeSource Self}, Path=Values}">
<UniformGrid>
<TextBox Text="{Binding [0]}" />
<TextBox Text="{Binding [1]}" />
<TextBox Text="{Binding [2]}" />
<TextBox Text="{Binding [3]}" />
<TextBox Text="{Binding [4]}" />
<TextBox Text="{Binding [5]}" />
<TextBox Text="{Binding [6]}" />
<TextBox Text="{Binding [7]}" />
<TextBox Text="{Binding [8]}" />
</UniformGrid>
</UserControl>
Code behind:
public partial class PartialSudokuGrid : UserControl {
public PartialSudokuGrid() {
InitializeComponent();
}
public int[] Values {
get {
return (int[])GetValue(ValuesProperty);
}
set {
SetValue(ValuesProperty, value);
}
}
public static DependencyProperty ValuesProperty = DependencyProperty.Register("Values", typeof(int[]), typeof(PartialSudokuGrid));
}
Fix:
Like MDoobie suggested, I removed the Self binding from the PartialGridView and cleared the codebehind file (no use anymore).
old:
<local:PartialSudokuGrid Values="{Binding ValuesVM}" />
new:
<local:PartialSudokuGrid DataContext="{Binding ValuesVM}" />
I think you set the Window's DataContext with this line DataContext="{Binding PartialSudokuGrid, Source={StaticResource Locator}}"
It is set the PartialSudokuGrid not the PartialSudokuGridVM (which has the ValuesVM property). Try to set the PartialSudokuGridVm as DataContext.
Related
I have a WPF Window that is meant to be used as a dialog. I am trying to use MVVM and have a view model as the DataContext of this dialog. So the simple confirmation dialog looks like:
<Window x:Class="Provision.Views.ConfirmationDialog"
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:Provision.Views"
mc:Ignorable="d"
Title="ConfirmationDialog" Height="450" Width="800"
DialogResult="{Binding DialogResult, Mode=TwoWay}">
<DockPanel>
<StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal" Margin="12" HorizontalAlignment="Right">
<Button Content ="{Binding Resources.Ok, FallbackValue=Ok}" IsDefault="True" Command="{Binding OkCommand}" Margin="12,0" Padding="12,6"/>
<Button Content ="{Binding Resources.Cancel, FallbackValue=Cancel}" IsCancel="True" Command="{Binding CancelCommand}" Padding="12,6"/>
</StackPanel>
<TextBlock Text="{Binding Resources.Confirmation, FallbackValue='Are you sure?'}" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</DockPanel>
</Window>
The problem I am having is binding to DialogResult. I get an error message
System.Windows.Markup.XamlParseException: 'A 'Binding' cannot be set on the 'DialogResult' property of type 'ConfirmationDialog'. A 'Binding' can only be set on a DependencyProperty of a DependencyObject.'
The property in the view model that it is binding to looks like:
private bool _dialogResult = false;
public bool DialogResult
{
get => _dialogResult;
set
{
if (_dialogResult != value)
{
_dialogResult = value;
RaisePropertyChanged();
}
}
}
I would eventually like to do something like
var result = new ConfirmationDialog().ShowDialog()
But I guess I don't understand the error message or how to overcome it. Can I make it a DependencyProperty in the view model? If so how?
Sorry about the headline but it was the best I could come up with. Let me explain my problem: I have a WPF application that has a Menu looking much like your standard top menu that only takes up 5% of the screen. Click a menu item and the view below changes. The menu control is home-brewed because of reasons: Dynamic changes to menu-items, weird UI that doesn't fit existing controls, etc.
The menu changing view part is done using a ContentControl that binds to a "CurrentMenuView" property. When a menu item is clicked, this happens (pseudo-code):
private async void Button_Pressed(...)
{
await MakeSomeVisualMenuChanges();
CurrentMenuView = new CarsView();
await MakeSomOtherStuff();
}
The problem is that some views take some time to load, which makes the other steps happen slow also. I'd like to start loading the "CarsView" but at the same time (not after) continue with the other changes. So the user can see stuff happening.
I can solve this by using Task.Run() but that seems wrong as it puts stuff in a different context.
What is the correct / better way of dealing with this?
EDIT:
Thanks for all answers, as I expected this is not easy to explain. Let me try with a simple example:
MainWindows.xaml:
<Window x:Class="WpfApp32.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"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="300" />
<RowDefinition Height="30" />
</Grid.RowDefinitions>
<Button Grid.Row="0" Width="50" Content="Click" Click="Button_Click" />
<ContentControl Grid.Row="1" Width="200" Height="200" Content="{Binding PageContent, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" />
<TextBlock Grid.Row="2" Text="Bottom" Width="300" x:Name="BottomText" />
</Grid>
</Window>
Code-Behind:
using System.Windows;
using System.ComponentModel;
namespace WpfApp32
{
public partial class MainWindow : Window, INotifyPropertyChanged
{
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
BottomText.Text = "AndNowforSomethingCompletelyDifferent";
PageContent = new UserControl1();
}
private object pageContent;
public object PageContent
{
get => pageContent;
set
{
pageContent = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(PageContent)));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
}
UserControl1.xaml:
<UserControl x:Class="WpfApp32.UserControl1"
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"
mc:Ignorable="d"
Loaded="UserControl_Loaded"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<TextBlock x:Name="CtrlTextBlock" Width="100"/>
</Grid>
</UserControl>
UserControl1.cs:
using System.Windows;
using System.Windows.Controls;
namespace WpfApp32
{
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
private void Init()
{
System.Threading.Thread.Sleep(2000);
CtrlTextBlock.Text = "Loaded";
}
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
Init();
}
}
}
So this is stripped from async etc and just showing the issue. When the button is pressed, the UserControl1 is loaded but it takes 2 seconds to load. Until then, the text in the "BottomText" element remains unset.
As I said before, I can solve this by doing something like this in the button click:
private void Button_Click(object sender, RoutedEventArgs e)
{
BottomText.Text = "AndNowforSomethingCompletelyDifferent";
System.Threading.Tasks.Task.Run(() => Application.Current.Dispatcher.Invoke(() => PageContent = new UserControl1()));
}
But not sure that is the way to go. So the basic issue here, is that a ContentControl is bound to a property and setting that property might take some time. While that is loading I don't want execution in the MainWindow to be halted (I want the BottomText element to display "AndNowforSomethingCompletelyDifferent" immediately).
Here's an example that simulates 3 seconds of loading... It's not an extremely complex UI and binding to complex DataTemplates, especially nested, can slow things a bit but normally the drag comes from pulling the data.
The trick is having a clever UI that keeps things moving but also lets the user know it's waiting on something else to continue. The infamous loading bar for example... Not that I would use that exact process but that's the right idea.
Note and disclaimer: I almost despise code behind unless it's in a custom control of some type; never in the view. I always prefer MVVM and using a ViewModel for binding; but not to build or control the UI only for the data the UI uses. All that said because this example is none of that. I simply made the controls on the view and put the code behind for answering this question, with example, as simple as possible.
The View
<Window x:Class="Question_Answer_WPF_App.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
Height="500"
Width="800">
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition />
</Grid.RowDefinitions>
<ToggleButton x:Name="menuButton"
Content="Menu"
Click="MenuButton_Click" />
<!--I do not recommend binding in the view like this... Make a custom control that does this properly.-->
<Grid x:Name="menu"
Visibility="{Binding IsChecked, Converter={StaticResource BooleanToVisibilityConverter}, ElementName=menuButton}"
VerticalAlignment="Top"
Grid.Row="1"
Background="Wheat">
<StackPanel x:Name="menuItems">
<TextBlock Text="simulated...." />
<TextBlock Text="simulated...." />
<TextBlock Text="simulated...." />
<TextBlock Text="simulated...." />
<TextBlock Text="simulated...." />
<TextBlock Text="simulated...." />
<TextBlock Text="simulated...." />
<TextBlock Text="simulated...." />
<TextBlock Text="simulated...." />
<TextBlock Text="simulated...." />
</StackPanel>
<StackPanel Name="menuLoading">
<TextBlock Text="Loading..."
FontSize="21" />
<ProgressBar IsIndeterminate="True"
Height="3" />
</StackPanel>
</Grid>
</Grid>
</Window>
Code Behind the View
using System.Threading.Tasks;
using System.Windows;
namespace Question_Answer_WPF_App
{
public partial class MainWindow : Window
{
public MainWindow() => InitializeComponent();
private Task SimulateLoadingResourcesAsnyc() => Task.Delay(3000);
private async void MenuButton_Click(object sender, RoutedEventArgs e)
{
menuItems.Visibility = Visibility.Collapsed;
menuLoading.Visibility = Visibility.Visible;
await SimulateLoadingResourcesAsnyc();
menuItems.Visibility = Visibility.Visible;
menuLoading.Visibility = Visibility.Collapsed;
}
}
}
I'm making an application using Caliburn.Micro(for easy data binding and stuff) and MahApps.Metro(for designing).
I've created a View name 'MainView' which has HamburgerMenu of MahApps.
My issue is data binding is working fine under HamburgerMenu.ContentTemplate tag
Here is my HamburgerMenu.ContentTemplate xaml.
<Page x:Class="Sample.Views.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cal="http://www.caliburnproject.org"
xmlns:mah="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks"
xmlns:utils="clr-namespace:Omni.WindowsClient.Utils"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Omni.WindowsClient.Views"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="600">
<Page.Resources>
<DataTemplate x:Key="HamburgerMenuItem"
DataType="{x:Type mah:HamburgerMenuItem}">
<Grid Height="48">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="48" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Image Margin="12"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Source="{Binding Glyph}"
Stretch="UniformToFill" />
<TextBlock Grid.Column="1"
VerticalAlignment="Center"
FontSize="16"
Foreground="White"
Text="{Binding Label}" />
</Grid>
</DataTemplate>
</Page.Resources>
<Grid>
<mah:HamburgerMenu x:Name="HamburgerMenuControl"
SelectedIndex="0"
ItemTemplate="{StaticResource HamburgerMenuItem}"
OptionsItemTemplate="{StaticResource HamburgerMenuItem}"
IsPaneOpen="True"
DisplayMode="CompactInline"
cal:Message.Attach="[Event ItemClick] = [Action ShowDetails(HamburgerMenuControl.SelectedItem)]"
DataContext="{Binding RelativeSource={RelativeSource self}}">
<mah:HamburgerMenu.ItemsSource>
<mah:HamburgerMenuItemCollection>
<mah:HamburgerMenuItem Label="System Status">
<mah:HamburgerMenuItem.Tag>
<iconPacks:PackIconFontAwesome Width="22"
Height="22"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Kind="Tasks" />
</mah:HamburgerMenuItem.Tag>
</mah:HamburgerMenuItem>
<mah:HamburgerMenuItem Label="Inbox">
<mah:HamburgerMenuItem.Tag>
<iconPacks:PackIconFontAwesome Width="22"
Height="22"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Kind="Inbox" />
</mah:HamburgerMenuItem.Tag>
</mah:HamburgerMenuItem>
<mah:HamburgerMenuItem.Tag>
<iconPacks:PackIconFontAwesome Width="22"
Height="22"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Kind="Certificate" />
</mah:HamburgerMenuItem.Tag>
</mah:HamburgerMenuItem>
</mah:HamburgerMenuItemCollection>
</mah:HamburgerMenu.ItemsSource>
<mah:HamburgerMenu.ContentTemplate>
<DataTemplate DataType="{x:Type mah:HamburgerMenuItem}">
<Grid utils:GridUtils.RowDefinitions="48,*">
<!--cal:Action.TargetWithoutContext="{Binding ElementName=HamburgerMenuControl, Path=DataContext}"-->
<Border Grid.Row="0"
Background="{DynamicResource MahApps.Metro.HamburgerMenu.PaneBackgroundBrush}">
<TextBlock x:Name="Header"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="24"
Foreground="White" />
<!--Text="{Binding Path=Header, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"-->
</Border>
<Frame Grid.Row="1"
cal:Message.Attach="RegisterFrame($source)"
DataContext="{x:Null}"
NavigationUIVisibility="Hidden" />
</Grid>
</DataTemplate>
</mah:HamburgerMenu.ContentTemplate>
</mah:HamburgerMenu>
</Grid>
</Page>
and respective view model code is:
using Caliburn.Micro;
using MahApps.Metro.Controls;
using System.Windows.Controls;
namespace Sample.ViewModels
{
public class MainViewModel : Screen
{
private readonly SimpleContainer _container;
private INavigationService _navigationService;
private string _header;
public string HeaderTitle
{
get { return _header; }
set
{
_header = value;
NotifyOfPropertyChange();
}
}
public MainViewModel(SimpleContainer container)
{
this._container = container;
DisplayName = "Main";
}
public void RegisterFrame(Frame frame)
{
_navigationService = new FrameAdapter(frame);
_container.Instance(_navigationService);
_navigationService.NavigateToViewModel(typeof(SystemStatusViewModel));
HeaderTitle = "System Status";
}
public void ShowDetails(HamburgerMenuItem menuItem)
{
switch (menuItem.Label)
{
case "System Status":
_navigationService.NavigateToViewModel(typeof(SystemStatusViewModel));
HeaderTitle = "System Status";
break;
case "Inbox":
_navigationService.NavigateToViewModel(typeof(InboxViewModel));
HeaderTitle = "Inbox";
break;
default:
break;
}
}
}
}
I want to change View in frame under HamburgerMenu.ContentTemplate when I click on menu item.
Like System Status view is SystemStatusView
and Inbox view is InboxView.
My code is working fine (it changes the view in frame and change the Header label too) if I don't use HamburgerMenu.ContentTemplate. But I want to use HamburgerMenu.ContentTemplate to work with HamburgerMenu.
Thanks!
If it's working fine if you don't use HamburgerMenu.ContentTemplate, but stops working when you do, the problem is probably with you overwriting the default template in a way that doesn't support all functionalities of a control.
I'd suggest you to use Blend to get the default HamburgerMenu.ContentTemplate, then just edit it to your needs, without changing too much (keep in mind that names of controls used as a template may have a crucial meaning, so be careful what you are editing).
If you don't know how to use Blend to get your control's template, here is a simple tutorial described in a documentation of Telerik controls (don't worry, it works the same for all controls). You just need to create copy of a HamburgerMenu.ContentTemplate, paste it to your application and you are good to go (editing).
I have a UserControl with a TextBox inside like this:
<UserControl x:Class="xxx.CommonControls.Views.InPlaceEdit"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:catel="http://catel.codeplex.com"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:dxe="http://schemas.devexpress.com/winfx/2008/xaml/editors"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
x:Name="parent"
mc:Ignorable="d">
<Border Background="Transparent" MouseLeftButtonDown="UIElement_OnMouseLeftButtonDown">
<TextBox x:Name="ButtonEdit"
Text="{Binding ElementName=parent,
Path=Value,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}">
</TextBox >
</Border>
</UserControl>
Usage:
<controls:InPlaceEdit Grid.Row="0"
Grid.Column="1"
Height="25"
Margin="5,0,0,5"
Value="{Binding SelectedPatient.Name, UpdateSourceTrigger=PropertyChanged}" />
Question is: how to move Validation errors to my TextBox? It's because all ValidationErrors are stored in my InPlaceEdit control, and not populated properly to TextBox.
(It's simplified view, but basically shows my problem. In my application I'm using ButtonEdit from DevExpress instead TextBox)
I have done it by removing Text binding from my child control and setting a binding to be exactly same as a parent:
this.Loaded += (sender, args) =>
{
var binding = BindingOperations.GetBinding(this, ValueProperty);
if (binding != null)
{
BindingOperations.SetBinding(ButtonEdit, DevExpress.Xpf.Editors.TextEditBase.TextProperty, binding);
}
};
I have following xaml code:
<Window x:Class="WPF_les_3.Oefening_4"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Oefening_4" Height="300" Width="300">
<StackPanel Width="auto" Margin="20px">
<ComboBox Width="100" SelectionChanged="ComboBox_Selected" x:Name="comboBox">
<ComboBoxItem>
<StackPanel Orientation="Horizontal">
<Rectangle Fill="Red" Height="20" Width="20"/>
<TextBlock Text=" Red"/>
</StackPanel>
</ComboBoxItem>
<ComboBoxItem>
<StackPanel Orientation="Horizontal">
<Rectangle Fill="Yellow" Height="20" Width="20"/>
<TextBlock Text=" Yellow"/>
</StackPanel>
</ComboBoxItem>
<ComboBoxItem>
<StackPanel Orientation="Horizontal">
<Rectangle Fill="Green" Height="20" Width="20"/>
<TextBlock Text=" Green"/>
</StackPanel>
</ComboBoxItem>
</ComboBox>
</StackPanel>
As you see, inside my ComboboxItems I have a rectangle and a textblock. Now I want to retreive the fill color of the rectangle (or the text of the textblock, it's the same) when my selectionchanged event is handled, so I can change the background of the window according to the selected color (which is the goal of the excercise).
To elaborate on my comment above, this is the Correct way to achieve what you need in WPF:
First of all, create a proper ViewModel that contains the list of available colors and a SelectedColor property:
public class ColorsViewModel
{
public ObservableCollection<string> Colors { get; private set; }
private string _selectedColor;
public string SelectedColor
{
get { return _selectedColor; }
set
{
_selectedColor = value;
MessageBox.Show("Selected Color: " + value); //message box here to show the code is actually working.
}
}
//... More code here in a moment
}
Then, make sure you populate the color collection with relevant data. In the case of colors specifically, WPF has built-in TypeConverters that can convert from (for example) string to System.Windows.Media.Color implicitly, therefore we can leverage that to simplify our code and use simple strings:
//Continuation of the above code
public ColorsViewModel()
{
Colors = new ObservableCollection<string>
{
"Red",
"Green",
"Blue",
"Yellow",
};
}
And finally create the UI in XAML using proper DataBinding:
<Window x:Class="WpfApplication3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<ComboBox ItemsSource="{Binding Colors}"
SelectedItem="{Binding SelectedColor}"
VerticalAlignment="Center" HorizontalAlignment="Center">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Rectangle Fill="{Binding}" Height="20" Width="20"/>
<TextBlock Text="{Binding}"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</Window>
Result:
The change event is fired and the ComboBox.SelectedItem has the info you need.
You have to analyze the SelectedItem like my following method:
private void comboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ComboBoxItem comboBoxItem = this.comboBox.SelectedItem as ComboBoxItem;
if (comboBoxItem != null)
{
StackPanel stackPanel = comboBoxItem.Content as StackPanel;
if(stackPanel != null && stackPanel.Children[0] is Rectangle)
{
var fill = (stackPanel.Children[0] as Rectangle).Fill;
}
}
}
Here you get the fill of the rectangle and can handle this or do your stuff.
But be patient, this code is created exactly for you sample (ComboBoxItem with Content StackPanel with Children[0] as Rectangle). Changes will iterrupt the process ;)