Resources in generic wpf window - c#

I am trying to use generic windows in WPF. I know how to create them, but I have hard time specify resources or anything else in the root element in such a window. Is this possible? You can use x:TypeArguments only in the root tag, so I am afraid that any definition outside of the root tag won't get recognized and handled without generic specification. I am missing something here?
This is a minimal (non)functional code:
MainWIndow.xaml
<local:ViewBase x:Class="WpfApp1.MainWindow"
x:TypeArguments="local:TestViewModel"
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:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<local:ViewBase.Resources>
<ResourceDictionary>
<Style x:Key="TEST" TargetType="TextBlock">
<Setter Property="Foreground" Value="Red"/>
</Style>
</ResourceDictionary>
</local:ViewBase.Resources>
<Grid>
<TextBlock Text="TEST" Style="{StaticResource TEST}" />
</Grid>
MainWindow.xaml.cs
public partial class MainWindow : ViewBase<TestViewModel>
{
public MainWindow()
: base(null)
{
InitializeComponent();
}
public MainWindow(TestViewModel vm)
: base(vm)
{
InitializeComponent();
}
}
SomeClass.cs
public class ViewBase<T> : Window where T : ViewModelBase
{
public ViewBase(T vm)
{
DataContext = vm;
}
}
public class ViewModelBase
{
public ViewModelBase()
{
}
}
public class TestViewModel : ViewModelBase
{
public TestViewModel()
{
}
}

Just write Window.Resources:
<local:ViewBase ...>
<Window.Resources>
<ResourceDictionary>
<Style x:Key="TEST" TargetType="TextBlock">
<Setter Property="Foreground" Value="Red"/>
</Style>
</ResourceDictionary>
</Window.Resources>
<Grid>
<TextBlock Text="TEST" Style="{StaticResource TEST}" />
</Grid>
</local:ViewBase>

Related

Prism's RegionManager.RequestNavigate is not working in WPF

I am writing a small WPF application and using Prism 7.1. It seems that everything worked, but the only _regionManager.RequestNavigate() does not work. When I click a button which binding to DelegateCommand, _regionManager.RequestNavigate() was called but nothing happens. This is an image when I use an overload of RequestNavigate() which has a navigationCallback parameter, NavigationService is null:
_regionManager is assigned from the constructors.
This happens not only one place, all calls to _requestManager.RequestNavigate() still like that.
This is how I setup:
App.xaml.cs:
public partial class App: PrismApplication
{
protected override void OnStartup (StartupEventArgs e)
{
base.OnStartup (e);
}
protected override void RegisterTypes (IContainerRegistry containerRegistry)
{
containerRegistry.RegisterForNavigation<DangNhapView> ();
containerRegistry.RegisterSingleton<IBusyMonitor, CompositeMainComponentsBusyMonitor> ();
containerRegistry.RegisterSingleton<INetRequester, HttpNetService> ();
containerRegistry.RegisterSingleton<IInternetConnectionChecker, MNBConnectionChecker> ();
}
protected override Window CreateShell ()
{
return Container.Resolve<MainWindow> ();
}
protected override void ConfigureModuleCatalog (IModuleCatalog moduleCatalog) {
}
}
MainWindow.xaml:
<Window x:Class="XemDiemSinhVienMain.Views.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"
xmlns:local="clr-namespace:XemDiemSinhVienMain.Views"
mc:Ignorable="d"
Title="Xem điểm sinh viên" Height="520" Width="940"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
xmlns:uc="clr-namespace:XemDiemSinhVien.Infrastructures.UserControls;assembly=XemDiemSinhVien.Infrastructures"
xmlns:constants="clr-namespace:XemDiemSinhVien.Infrastructures.Constants;assembly=XemDiemSinhVien.Infrastructures"
xmlns:xemDiemSinhVienMain="clr-namespace:XemDiemSinhVienMain"
Icon="../app_icon.ico">
<WindowChrome.WindowChrome>
<WindowChrome GlassFrameThickness="1"
CornerRadius="0"
CaptionHeight="0"
UseAeroCaptionButtons="False"
ResizeBorderThickness="5"/>
</WindowChrome.WindowChrome>
<!-- https://stackoverflow.com/questions/2967218/window-out-of-the-screen-when-maximized-using-wpf-shell-integration-library/2975574 -->
<Window.Template>
<ControlTemplate TargetType="{x:Type local:MainWindow}">
<Border BorderBrush="Green">
<Border.Style>
<Style TargetType="{x:Type Border}">
<Setter Property="BorderThickness" Value="0"/>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:MainWindow}}, Path=WindowState}" Value="Maximized">
<Setter Property="BorderThickness" Value="8"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<!-- Window's content -->
<Grid Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="32"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ContentControl Grid.Row="1"
prism:RegionManager.RegionName="{x:Static constants:RegionNames.MainContentRegion}"/>
<Button Content="Switch to NavigationTestView"
Command="{Binding SwitchToNavigationTestViewCommand}"
HorizontalAlignment="Center"
VerticalAlignment="Top"
Margin="10"
Grid.Row="1"/>
<uc:WindowTitleBar Grid.Row="0"
MinimizeClick="WindowTitleBar_OnMinimizeClick"
CloseClick="WindowTitleBar_OnCloseClick"
MouseLeftButtonDown="WindowTitleBar_OnMouseLeftButtonDown"/>
</Grid>
</Border>
</ControlTemplate>
</Window.Template>
</Window>
MainWindowViewModel:
public class MainWindowViewModel : BindableBase
{
private IRegionManager _regionManager;
public DelegateCommand SwitchToNavigationTestViewCommand { get; private set; }
public MainWindowViewModel (IRegionManager regionManager) {
_regionManager = regionManager;
SwitchToNavigationTestViewCommand = new DelegateCommand (() => {
_regionManager.RequestNavigate (RegionNames.MainContentRegion, "DangNhapView");
});
}
}
So how can I fix this problem? Thank you for reading my question.

binding value to template property

I have a serious problem on binding value to property.
This is my source code.
public partial class MainPage : Page,Autodesk.Revit.UI.IDockablePaneProvider
{
....
public System.Windows.Media.Brush BCol { get; set; }
.....
}
<ListBox Style = "{DynamicResource ListBoxStyle}">
...
</ListBox>
<Style x:Key="ListBoxStyle" TargetType="{x:Type ListBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBox}">
<Grid Background="{Binding BCol}">
...
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I want to bind BCol to grid background but it doesn't work.
How should I do?
Depending on where BCol is set, you might need to implement INotifyPropertyChanged interface. You also need to make sure that you are binding to the view model that is assigned to your DataContext.
You can also create a DependencyProperty. I have posted both solutions below. DependencyProperty one is probably the solution that you want.
INotifyPropertyChanged solution:
XAML
<Page x:Class="WpfTest.MainPage"
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:local="clr-namespace:WpfTest"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
Title="MainPage">
<Grid>
<Grid.Resources>
<Style x:Key="ListBoxStyle" TargetType="{x:Type ListBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBox}">
<Grid Background="{Binding BCol}">
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
<ListBox Style = "{DynamicResource ListBoxStyle}">
</ListBox>
</Grid>
</Page>
Code behind:
using System.ComponentModel;
using System.Windows.Controls;
using System.Windows.Media;
namespace WpfTest
{
/// <summary>
/// Interaction logic for MainPage.xaml
/// </summary>
public partial class MainPage : Page, INotifyPropertyChanged
{
private Brush bCol;
public System.Windows.Media.Brush BCol
{
get { return bCol; }
set
{
bCol = value;
RaisePropertyChanged("BCol");
}
}
public MainPage()
{
InitializeComponent();
DataContext = this; //This is a hack, you should really create a separate view model
BCol=new SolidColorBrush(Colors.Blue);
}
public event PropertyChangedEventHandler PropertyChanged= delegate { };
void RaisePropertyChanged(string name)
{
PropertyChanged(this,new PropertyChangedEventArgs(name));
}
}
}
DependencyProperty solution
XAML
<Page x:Class="WpfTest.MainPage"
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:local="clr-namespace:WpfTest"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
Title="MainPage">
<Grid>
<Grid.Resources>
<Style x:Key="ListBoxStyle" TargetType="{x:Type ListBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBox}">
<Grid Background="{Binding RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType={x:Type local:MainPage}}, Path=BCol}">
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
<ListBox Style = "{DynamicResource ListBoxStyle}">
</ListBox>
</Grid>
</Page>
Code behind
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace WpfTest
{
/// <summary>
/// Interaction logic for MainPage.xaml
/// </summary>
public partial class MainPage : Page
{
private Brush bCol;
public static DependencyProperty BColProperty =DependencyProperty.Register("BCol", typeof(Brush),typeof(MainPage));
public Brush BCol
{
get { return (Brush)this.GetValue(BColProperty); }
set { this.SetValue(BColProperty, value); }
}
public MainPage()
{
InitializeComponent();
BCol=new SolidColorBrush(Colors.Blue);
}
}
}
Hope this helps.
you need to add this to the top of your xaml with all of your xmlns's
DataContext="{Binding RelativeSource={RelativeSource Self}}"

Load user control in tab item

i am trying to load user control in tab item dynamically but i am unable to do so i am using below code .I have visited various posts also but i have got the below way please let me know where i am wrong:
User control:
<UserControl x:Class="WpfApplication1.UserControl2"
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:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Button Content="welcome" Height="20" Width="70"></Button>
</Grid>
</UserControl>
ViewMOdel:
namespace WpfApplication1
{
class Usercontrol2ViewModel
{
public ObservableCollection<TabItem> Tabs { get; set; }
public Usercontrol2ViewModel()
{
Tabs = new ObservableCollection<TabItem>();
//Tabs.Add(new TabItem { Header = "Overview", Content = new OverviewViewModel() }); How to load a usercontrol here if it's in the ItemCollection?
Tabs.Add(new TabItem { Header = "Overview", Content = new UserControl2() });
}
}
public class TabItem
{
public string Header { get; set; }
public object Content { get; set; } // object to allow all sort of items??
}
}
MainPage:
<TabControl x:Name="MyTabControl"
ItemsSource="{Binding Tabs}">
<TabControl.Resources>
<DataTemplate DataType="{x:Type local:Usercontrol2ViewModel}">
<local:UserControl2></local:UserControl2>
</DataTemplate>
</TabControl.Resources>
<TabControl.ItemContainerStyle>
<Style TargetType="TabItem">
<Setter Property="Header" Value="{Binding Header}" />
</Style>
</TabControl.ItemContainerStyle>
</TabControl>
I found the issue below is the solution of code patch that needs to be correct above posted code
<Style TargetType="TabItem">
<Setter Property="Header" Value="{Binding Header}" />
<Setter Property="Content" Value="{Binding Content}"></Setter>
</Style>

WPF Boolean Trigger

I have a boolean in the Window class of my WPF application. How can I target a trigger depending on whether this boolean is true or false?
<Grid>
<Grid.Triggers>
<Trigger ... />
</Grid.Triggers>
</Grid>
Thanks.
in *.cs file:
public partial class MainWindow : INotifyPropertyChanged
{
public MainWindow()
{
DataContext = this;
InitializeComponent();
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
public bool Flag { get; set; }
private void ButtonClick(object sender, RoutedEventArgs e)
{
Flag = true;
OnPropertyChanged("Flag");
}
protected void OnPropertyChanged(string property)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
in xaml form:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
Width="525"
Height="350">
<Window.Resources>
<Style TargetType="Grid">
<Style.Triggers>
<DataTrigger Binding="{Binding Flag}" Value="True">
<Setter Property="Background" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Button Click="ButtonClick" Content="Click Me" />
</Grid>
</Window>
You can use a DataTrigger. I think you need to use it within a style or template though.
Alternatively, you can capture the changes in the code behind.

How to put a MouseDown event in a Style?

This works:
XAML:
<Window x:Class="Test239992.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<StackPanel>
<TextBlock Tag="1" Text="Customers" MouseDown="Handle_Click"/>
<TextBlock Tag="2" Text="Appointments" MouseDown="Handle_Click"/>
</StackPanel>
</Window>
Code Behind:
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace Test239992
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
private void Handle_Click(object sender, MouseButtonEventArgs e)
{
int id = Int32.Parse(((TextBlock)sender).Tag.ToString());
MessageBox.Show("you chose id " + id.ToString());
}
}
}
But how do I put the MouseDown event in a style, this gives me the error "Cannot find the Style Property 'MouseDown' on the type 'System.Windows.Controls.TextBlock'":
<Window x:Class="Test239992.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<Style TargetType="{x:Type TextBlock}" x:Key="ClickableTextBlockStyle">
<Setter Property="MouseDown" Value="Handle_Click" />
</Style>
</Window.Resources>
<StackPanel>
<TextBlock Tag="1" Text="Customers" Style="{DynamicResource ClickableTextBlockStyle}"/>
<TextBlock Tag="2" Text="Appointments" Style="{DynamicResource ClickableTextBlockStyle}"/>
</StackPanel>
</Window>
Try EventSetter :)
<Style TargetType="{x:Type TextBlock}" x:Key="ClickableTextBlockStyle">
<EventSetter Event="MouseDown" Handler="Handle_Click" />
</Style>
Have a look at Triggers in WPF:
http://mark-dot-net.blogspot.com/2007/07/creating-custom-wpf-button-template-in.html

Categories