I have built an application in MVVM using Caliburn Micro. I currently have the closetab working on all my tabs, and it closes all tabs apart from the first three, which are Home, Payment, Notes however, I would like it to NOT show the close tab icon on the first three tabs as shown in my AppViewModel code:
<TabControl x:Name="Items" Grid.Row="1" Visibility="{Binding Visibility, Converter={StaticResource boolToVis}}">
<TabControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<!-- The Tab Names Binding with DisplayName-->
<TextBlock Text="{Binding DisplayName}" />
<!-- The Tab Close Icon-->
<Button Content="x" x:Name="CloseTab" cal:Message.Attach="CloseTab" Style="{DynamicResource appTabCloseButton}" Visibility="{Binding Visibility, Converter={StaticResource boolToVis}}"/>
</StackPanel>
</DataTemplate>
</TabControl.ItemTemplate>
</TabControl>
My AppViewModel code behind for the close tab:
public void CloseTab()
{
if(ActiveItem.DisplayName == "Home" || ActiveItem.DisplayName == "Payment" || ActiveItem.DisplayName == "Notes")
{
MessageBox.Show("This Tab Cannot Be closed.","Permanent Tab");
} else {
DeactivateItem(ActiveItem, close: true);
}
}
My App.xaml code for the boolToVis:
<Application x:Class="WPF.Test.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WPF.Test.App">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary>
<local:Bootstrapper x:Key="bootstrapper" />
<BooleanToVisibilityConverter x:Key="boolToVis" />
</ResourceDictionary>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Global.WPF.UserControls;component/Resources/brushes.xaml" />
<ResourceDictionary Source="/Global.WPF.UserControls;component/Resources/CommonControls.xaml" />
<ResourceDictionary Source="/Global.WPF.UserControls;component/Resources/menuItems.xaml" />
<ResourceDictionary Source="pack://application:,,,/Fluent;Component/Themes/Generic.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
and finally the visibility for the binding:
bool _visibility;
public bool Visibility
{
get { return _visibility; }
set
{
_visibility = value;
NotifyOfPropertyChange("Visibility");
}
}
I would be happy for any suggestions as I'm totally lost!!
Create a Guard Panel that can be used to show/hide the button.
<TabControl x:Name="Items" Grid.Row="1" Visibility="{Binding Visibility, Converter={StaticResource boolToVis}}">
<TabControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<!-- The Tab Names Binding with DisplayName-->
<TextBlock Text="{Binding DisplayName}" />
<Border x:Name="CanCloseTab">
<!-- The Tab Close Icon-->
<Button Content="x" x:Name="CloseTab" cal:Message.Attach="CloseTab" Style="{DynamicResource appTabCloseButton}" />
</Border>
</StackPanel>
</DataTemplate>
</TabControl.ItemTemplate>
</TabControl>
Then create a guard property
public bool CanCloseTab {
get {
return !(ActiveItem.DisplayName == "Home"
|| ActiveItem.DisplayName == "Payment"
|| ActiveItem.DisplayName == "Notes");
}
}
By convention the view should automatically bind the CanCloseTab property to the visibility of the panel (Border) so that when false it will not display. If the panel was not there the guard property would have also automatically disabled the button.
This should now allow the CloseTab method to be refactored for simplicity.
public void CloseTab() {
if(CanCloseTab) {
DeactivateItem(ActiveItem, close: true);
}
}
Related
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 problem with my small WPF tray icon which has a context menu assigned. If I do a right-click on the tray icon the context menu opens and you see a text box containing an integer value. Now when clicking to the "Create Instance" field the integer should increment by one. The new value should be shown in the textbox. On startup the correct inital value is shown in the textbox but changes during runtime are not reflected to the UI. I think there is a data binding problem... The click event is caught and even the value is incremented but the textbox does not recognize the new value...
I have no Main Window the application should only be a tray icon context menu.
App.xaml.cs
public partial class App : Application
{
// This objects are global
private TaskbarIcon notifyIcon;
private INotificationBarMessage message = null;
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
//create the notifyicon (a resource declared in NotifyIconResources.xaml)
notifyIcon = (TaskbarIcon) FindResource("Key_NotifyIcon");
notifyIcon.DataContext = this;
message = new NotificationBarMessage(notifyIcon);
message.Show(TextType.Startup);
}
}
ResourceContextMenu.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:tb="http://www.hardcodet.net/taskbar"
xmlns:local="clr-namespace:UserInterface.ViewModel"
x:Class="UserInterface.ViewModel.EventHandlerUI">
<ContextMenu x:Shared="false" x:Key="My_ContextMenu">
<ContextMenu.DataContext>
<local:ContextMenuModel /> <!-- reference to ContextMenuModel.cs -->
</ContextMenu.DataContext>
<!-- DataContext="{Binding PlacementTarget.DataContext,
RelativeSource={RelativeSource Self}} -->
<ContextMenu.Resources>
<local:ConverterBoolToVisibility x:Key="BoolToHiddenConverter"
TrueValue="Visible"
FalseValue="Hidden" />
<local:ConverterIntToString x:Key="IntToStringConverter" />
</ContextMenu.Resources>
<TextBlock Text="Status"/>
<Separator/>
<MenuItem Header="Create Instance"
MouseEnter="CreateInstance_OverEnter"
MouseLeave="CreateInstance_OverExit"
Click="CreateInstance_Click"
StaysOpenOnClick="True" />
<!-- Command="{Binding ShowWindowCommand}" -->
<MenuItem Header="Open Window"
StaysOpenOnClick="True"
Command="{Binding Commands.ShowWindowCommand}" />
<MenuItem Header="IP-Address"
Name="MenuItem_IPAddress"
Visibility="{Binding EventData.IsEnabled, Mode=TwoWay,
Converter={StaticResource BoolToHiddenConverter}}"
StaysOpenOnClick="True"/>
<TextBox Width="100"
Text="{Binding Path=EventData.Counter,
UpdateSourceTrigger=PropertyChanged, Mode=TwoWay,
Converter={StaticResource IntToStringConverter}}"/>
<Separator/>
<MenuItem Header="Exit"
Command="{Binding Path=Commands.ExitApplicationCommand}" />
</ContextMenu>
<!-- Tray Icon -->
<!-- the application's NotifyIcon - started from App.xaml.cs.
Declares its own view model. -->
<tb:TaskbarIcon x:Key="Key_NotifyIcon"
x:Name="My_NotifyIcon"
IconSource="/View/gfx/_UserInterface.ico"
ToolTipText="tip"
ContextMenu="{StaticResource My_ContextMenu}"/>
App.xaml
<Application x:Class="UserInterface.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
ShutdownMode="OnExplicitShutdown">
<Application.Resources>
<!-- Note that this application does not have a StartupUri declared,
so no Window is automatically loaded.
Also, the ShutdownMode was set to explicit,
so we have to close the application programmatically. -->
<!-- merge NotifyIcon and related stuff into the application -->
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ResourceContextMenu.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
Here is the code where I fire the property changed event:
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private int _counter = 34;
public int Counter
{
get
{
return this._counter;
}
set
{
if (value != this._counter)
{
this._counter = value;
NotifyPropertyChanged();
}
}
}
Any help would be appreciated.
I have a single MetroWindow which loads with default Color. I have an option for user to change the style. In the window I use a Content control to set the user control dynamically from code behind when initializing this window (This window is initialized from another application so there is no app.xaml and I use the resources in the window itself). The code of the main windows is below. In the User Control I am using some labels and a tab control. On the window I have an option for user to be able to change the theme choosing from available themes (as in your demo project). In all labels I use dynamics resources.
When the window loads for first time the default color is applied and all inner controls have the same theme as well. When I change the theme from window top, the window border, title, glow changes but the inner control stays the old theme (like the tab control headers etc.) I have tried everything but that does not seem to change.
Below is my code:
<Controls:MetroWindow x:Class="Test.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
Title="MainWindow" Height="300" Width="300" ShowMaxRestoreButton="False" ShowMinButton="False"
BorderBrush="{DynamicResource HighlightBrush}"
GlowBrush="{DynamicResource HighlightBrush}" WindowStartupLocation="CenterScreen"
ResizeMode="NoResize" WindowTransitionsEnabled="False" TitleCaps="True"
BorderThickness="1">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colors.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/Blue.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseLight.xaml" />
<ResourceDictionary Source="/Test;component/Resources/Icons.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Border Margin="5" BorderBrush="Transparent" BorderThickness="0">
<ContentControl x:Name="ChildContentControl"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
</ContentControl>
</Border>
</Controls:MetroWindow>
My code behind for the window:
public partial class MainWindow : MetroWindow
{
public MainWindow()
{
InitializeComponent();
this.Initialize();
}
public MainWindow(string title, UserControl childControl)
{
try
{
InitializeComponent();
this.Title = title;
this.ChildContentControl.Content = childControl;
}
catch (Exception de)
{
throw de;
}
}
}
My User control XAML
<UserControl x:Class="Test.UCDemo"
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"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:local="clr-namespace:Test"
xmlns:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Test;component/Resources/Icons.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Border>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<DockPanel Grid.Row="0" LastChildFill="True">
<Grid Height="60" DockPanel.Dock="Bottom">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="5"/>
</Grid.ColumnDefinitions>
<Button Grid.Column="1" Margin="5,0,5,0" Width="50" Height="50"
Style="{DynamicResource MetroCircleButtonStyle}" Command="{Binding OKCommand}">
<Rectangle Width="20"
Height="20"
Fill="{Binding Path=Foreground, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}}">
<Rectangle.OpacityMask>
<VisualBrush Stretch="Fill"
Visual="{StaticResource appbar_check}" />
</Rectangle.OpacityMask>
</Rectangle>
</Button>
</Grid>
<Grid DockPanel.Dock="Top" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="Transparent"
SnapsToDevicePixels="True"
ScrollViewer.HorizontalScrollBarVisibility="Hidden" ScrollViewer.VerticalScrollBarVisibility="Hidden">
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.Resources>
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.AnimatedSingleRowTabControl.xaml" />
</Grid.Resources>
<TabControl Margin="0,10,0,0" TabStripPlacement="Left" ItemsSource="{Binding Catalogs}" SelectedItem="{Binding SelectedCatalog}">
<TabControl.ItemTemplate>
<!-- this is the header template-->
<DataTemplate>
<TextBlock Text="{Binding Path=CaptionCat}" Foreground="{DynamicResource HighlightBrush}" FontSize="14" Margin="0,0,0,10" />
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding DataContext.SelectedCatalog.Books,RelativeSource={RelativeSource AncestorType={x:Type TabControl}}}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel ScrollViewer.VerticalScrollBarVisibility="Disabled"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Controls:Tile Height="125" Width="300" IsEnabled="{Binding IsEnabled}" Title="{Binding CaptionBook}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</Grid>
</Grid>
</DockPanel>
</Grid>
</Border>
</UserControl>
My User control Code behind:
public partial class UCDemo : UserControl
{
private VMDemo CatalogVM { set; get; }
public UCDemo()
{
try
{
InitializeComponent();
this.DataContext = new VMDemo();
}
catch (Exception de)
{
throw de;
}
}
}
And Finally here is how I call the window and embedded user control from hosted application code:
private void ShowDemoUI()
{
try
{
var child = new UILibrary.UCDemo();
UILibrary.MainWindow window = new UILibrary.MainWindow("Book catalog", child);
window.Height = 450;
window.Width = 700;
window.ShowDialog();
}
catch (Exception de)
{
throw de;
}
}
I think you have 2 options to solve this.
Create your Test.UCDemo as DataTemplate for the VMDemo type and pass the VMDemo for this template to the Content, so your ContentControl will automatically do the magic for you (it's just only a suggestion, i don't tested it)
Put the resources in your Test.UCDemo too.
You need to move all your ResourceDictionaries in the App.xaml
After that I think you need to look at the Theme Manager.
Here is what I've done. In this example all my Content Control have the save Theme even if I change the Theme with a button click:
public ShellView()
{
this.InitializeComponent();
var theme = ThemeManager.DetectAppStyle(Application.Current);
ThemeManager.ChangeAppStyle(Application.Current, ThemeManager.GetAccent("Blue"), theme.Item1);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var theme = ThemeManager.DetectAppStyle(Application.Current);
ThemeManager.ChangeAppStyle(Application.Current, ThemeManager.GetAccent("Cyan"), theme.Item1);
}
The code need to be in the code behing of your Window (In my case it's ShellView.cs) for you I will assume that it's MainWindow.cs
Here is an other example with a Custom Theme.
public ShellView()
{
this.InitializeComponent();
ThemeManager.AddAccent("YourAccent", new Uri("pack://application:,,,/YourAccent.xaml"));
// Set your Custom Theme when the Window start
var theme = ThemeManager.DetectAppStyle(Application.Current);
ThemeManager.ChangeAppStyle(Application.Current, ThemeManager.GetAccent("YourAccent"), theme.Item1);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
// Change the Theme to Cyan on a simple button click
var theme = ThemeManager.DetectAppStyle(Application.Current);
ThemeManager.ChangeAppStyle(Application.Current, ThemeManager.GetAccent("Cyan"), theme.Item1);
}
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.
Normally I bind ObservableCollection to my own classes. But in this case I need to bind ObservableCollection of Strings in ListBox using MVVM into WPF.
My xml is
<Window x:Class="ListBoxDynamic.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"
xmlns:vm="clr-namespace:ListBoxDynamic.ViewModel">
<Grid Margin="0,0,-8,0">
<ListBox Width="100" Height="90" ItemsSource="{Binding ListOfItems}">
<ListBox.ItemTemplate>
<DataTemplate>
<ToggleButton Command="{Binding SelectItemCommand}" CommandParameter="{Binding ElementName=Item}" >
<ToggleButton.Template>
<ControlTemplate TargetType="ToggleButton">
<TextBlock x:Name="Item" Text="{Binding What I must to write?}" />
</ControlTemplate>
</ToggleButton.Template>
</ToggleButton>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
My MainViewModel
private ObservableCollection<string> _listOfItems = new ObservableCollection<string>();
public ObservableCollection<string> ListOfItems
{
get { return _listOfItems; }
set { _listOfItems = value; RaisePropertyChanged("ListOfItems"); }
}
public ICommand SelectItemCommand { get; private set; }
int counter = 1;
public MainViewModel()
{
ListOfItems.Add("Add new Item");
SelectItemCommand = new RelayCommand<object>((x) => ExecuteSelectItemCommand(x));
}
But I don't know that I must to write in Binding TextBlock into ToggleButton.
Since data which back each ListBoxItem is string, hence DataContext of each ListBoxItem will be string.
Hence doing <TextBlock x:Name="Item" Text="{Binding }" /> will show you the string backing the listboxitem in the textblock
there are few issues I notices
the command is available in the view model instead of the data item, so use relative source to bind to command
"{Binding}" can be used to refer to current Item, so no need to use elementname syntax
then instead of placing a textbox inside toggle button you can make use of content presenter to make it more flexible
so this could go like this
<ListBox Width="100"
Height="90"
ItemsSource="{Binding ListOfItems}">
<ListBox.ItemTemplate>
<DataTemplate>
<ToggleButton Command="{Binding SelectItemCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListBox}}"
CommandParameter="{Binding}"
Content="{Binding}">
<ToggleButton.Template>
<ControlTemplate TargetType="ToggleButton">
<ContentPresenter />
</ControlTemplate>
</ToggleButton.Template>
</ToggleButton>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>