I have this button from Main window.xaml need to call it from another class
i made it just like first answer
How to make a control in XAML public in order to be seen in other classes
<Window x:Class="USD.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="450" Width="525">
<Button ToolTip="Answer Call" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="107,82,0,0" x:Name="answerCall" Click="answerCall_Click" Visibility="Hidden" x:FieldModifier="public">
<StackPanel Orientation="Horizontal" >
<Image Width="35" Height="35" Source="Images/unnamed.png" RenderTransformOrigin="4.075,0.607">
</Image>
</StackPanel>
<Button.Template>
<ControlTemplate TargetType="Button">
<Grid>
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>
</Button.Template>
</Button>
but when i checked it from any .cs class just like that
MainWindow.answerCall.Visibility.Visible;
give errors
i fixed it by this in C# code
DispatcherPriority.Background,
new Action(() => ((MainWindow)System.Windows.Application.Current.MainWindow).answerCall.Visibility = Visibility.Visible));
If you use a controller/viewmodel, you shouldn't have any code behind, instead of that, you should work with bindable properties and commands, implementing INotifyPropertyChanged interface, in some base class if you want.
Related
In my application I have a control which renders a number of blocks on a timeline view (like a calendar). One can provide a template for the blocks by giving the timeline an appropriate DataTemplate.
I would like to separate the block DataTemplate from the main timeline view, putting the block into its own XAML. As such, I've created a XAML for the Block (called Block.xaml) and wrapped the DataTemplate inside a ResourceDictionary, inside this XAML.
I've added a code behind to the XAML (called Block.xaml.cs) in which I need to access some of the elements in the block. The issue is that ResourceDictionaries seem to hide the elements from the codebehind such that I can't access them. I can't use a UserControl instead - this seems to not work.
How can I access the elements of the Block DataTemplate from the code behind?
Many thanks in advance for your help.
Block.xaml:
<ResourceDictionary x:Class="Project.Windows.MainInterface.TimelinePanel.Block" 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:local="clr-namespace:Project.Windows.MainInterface.TimelinePanel" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" xmlns:converters="clr-namespace:Project.Converters" >
<DataTemplate x:Key="ItemBlockTemplate">
<Grid Name="BlockParent" Width="Auto" Height="Auto" MinHeight="50" ClipToBounds="True" SizeChanged="BlockParent_OnSizeChanged">
<Border Panel.ZIndex="3" BorderBrush="{DynamicResource BackgroundGreyLight}" BorderThickness="1" CornerRadius="1" />
<Grid Margin="1" Background="{DynamicResource BlockBackgroundGradient}" d:LayoutOverrides="Width">
<TextBlock x:Name="blockName" Height="20" Margin="4,0,4,0" Padding="3" VerticalAlignment="Top" Panel.ZIndex="3" FontSize="10" Foreground="{DynamicResource TextLight}" Text="{Binding blockName}" TextTrimming="CharacterEllipsis" Visibility="Visible" />
<TextBlock x:Name="Duration" Margin="0,2,4,2" Padding="0,0,3,0" HorizontalAlignment="Right" VerticalAlignment="Bottom" Panel.ZIndex="5" FontSize="10" Foreground="{DynamicResource TextLight}" Text="{Binding FormattedDuration}" ToolTip="{Binding Duration}" />
<Grid Background="#FF0FA8FF" Opacity="0.7" />
</Grid>
</Grid>
</DataTemplate>
Snippet of the Timeline in the main interface:
...
<timeLineTool:TimeLineControl x:Name="Timeline" Height="50" MinWidth="50" Margin="0,0,12,0" HorizontalAlignment="Left" VerticalAlignment="Top" Items="{Binding Timeline}" SnapsToDevicePixels="True" UnitSize="{Binding UnitSize}" UseLayoutRounding="True">
<timeLineTool:TimeLineControl.ItemTemplate>
<DataTemplate DataType="{x:Type local:BlockItemViewModel}">
<ContentControl>
<ContentPresenter Margin="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Content="{Binding}" ContentTemplate="{StaticResource ItemBlockTemplate}" />
</ContentControl>
</DataTemplate>
</timeLineTool:TimeLineControl.ItemTemplate>
</timeLineTool:TimeLineControl>
...
...If I could use a UserControl instead of a ResourceDictionary for my Block, this would solve the problem, as all elements are automatically publicly available in the code behind for usercontrols.
Sample XAML:
<Window.Resources>
<ControlTemplate x:Key="ResourceName" TargetType="{x:Type Label}">
<Label Foreground="White" Content="{iconPacks:PackIconFontAwesome plug,Height=40,Width=40}"/>
</ControlTemplate>
</Window.Resources>
Code behind
ControlTemplate Dictionary:
private Dictionary<string, ControlTemplate> collection
{
get
{
Dictionary<string, ControlTemplate> controlTemplates = new Dictionary<string, ControlTemplate>();
controlTemplates.Add("ResourceName", FindResource("ResourceName") as ControlTemplate);
return controlTemplates;
}
}
Use ControlTemplate:
Label LBDisConnect = new Label();
LBDisConnect.Template = collection["ResourceName"];
LoginInfo.Children.Add(LBDisConnect);
I have a MainWindow.Xaml file. And one usercontrol PatientWindow.Xaml. How to load the patient window in mainwindow in MVVM architecture?
MainWindow.Xaml
<Window x:Class="PatientAdminTool.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:PatientAdminTool.ViewModel"
xmlns:v="clr-namespace:PatientAdminTool.View"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
ResizeMode="CanResizeWithGrip"
WindowStyle="None"
WindowState="Normal"
Title="PatientAdmin Tools"
Height="750"
Width="1400"
AllowsTransparency="True" MouseLeftButtonDown="OnMouseLeftButtonDown" BorderThickness="1" BorderBrush="#555252" >
<WindowChrome.WindowChrome>
<WindowChrome
CaptionHeight="0"
/>
</WindowChrome.WindowChrome>
</Window>
PatientWindow.xaml
Usercontrol window is mentioned in below
<UserControl x:Class="PatientAdminTool.View.PatientWindow"
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:vm="clr-namespace:PatientAdminTool.ViewModel"
xmlns:v="clr-namespace:PatientAdminTool.View"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300" >
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<DockPanel Grid.Row="0" LastChildFill="True" Height="40" Background="#646161" >
<StackPanel DockPanel.Dock="Left" Orientation="Horizontal">
<TextBlock Margin=" 10,5,0,0" HorizontalAlignment="Center" Text="Patients" FontSize="16" TextAlignment="Center" VerticalAlignment="Center" Foreground="#FFFFFF"/>
</StackPanel>
<StackPanel Margin="10,10,0,0" DockPanel.Dock="Right" Background="Transparent" Orientation="Vertical" HorizontalAlignment="Right" VerticalAlignment="Top" Width="50" >
<StackPanel Background="Transparent" Orientation="Horizontal" HorizontalAlignment="Right">
<Button Focusable="False" ToolTip="Close" VerticalAlignment="Center" Background="#646161" BorderThickness="0" BorderBrush="Transparent" Padding="-4" Click="Button_Click" >
<Button.Content>
<Grid Width="45" Height="23">
<TextBlock Foreground="White" Text="r" FontFamily="Marlett" FontSize="20" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Grid>
</Button.Content>
<Button.Template>
<ControlTemplate TargetType="Button">
<ContentPresenter Content="{TemplateBinding Content}"/>
</ControlTemplate>
</Button.Template>
</Button>
</StackPanel>
</StackPanel>
</DockPanel>
</Grid>
</UserControl>
So I need to load the patient window above of main window using MVVM. Here I need to write load event in corresponding View Model. Please help me to do this.
Just add a ControlPresenter at MainWindow.
<ContentPresenter Content="{Binding YouTypeHere}">
<ContentPresenter.Resources>
<DataTemplate DataType="{x:Type fristViewModel1Type}">
<youControlForViewModel1 />
</DataTemplate>
<DataTemplate DataType="{x:Type secondViewModel2Type}">
<youControlForViewModel2 />
</DataTemplate>
</ContentPresenter.Resources>
</ContentPresenter>
And you could change Views via binding different VM to ContentPresenter.
So you want to open a new child window using MVVM? I assume you would open it from MainWindowViewModel.
Solution 1: without strict MVVM
Sometimes its fine to open it directly from the ViewModel:
private void OnOpenPatientWindowCommandExecute()
{
var o = new PatientWindow();
o.ShowDialog();
}
For this you would have to change PatientWindow from UserControl to a Window.
Solution 2: strict MVVM
The solutions following strict MVVM are a little more complex. In the solution I write here you would have to use a Service, add it to your MainWindowViewModel and bind a control from the view to a Command in the ViewModel. Also, its written as if you are using Dependency Injection, that's why you see the service injected in the constructor. You can avoid this by just instantiating the service in the constructor.
MainWindowViewModel.cs
using Prism.Wpf.Commands; // For easy commands
using PatientAdminTool.Services; // Where you put your new service
public class MainWindowViewModel
{
private IShowDialogService _ShowDialogService;
public MainWindowViewModel(IShowDialogService showDialogService)
{
_ShowDialogService = showDialogService;
// Or do: _ShowDialogService = new ShowDialogService();
// But that's not a good practice and won't let you test
// this ViewModel properly.
OpenPatientWindowCommand = new DelegateCommand(OnOpenPatientWindowCommandExecute);
}
public ICommand OpenPatientWindowCommand { get; private set; }
private void OnOpenPatientWindowCommandExecute()
{
_ShowDialogService.ShowPatientWindow();
}
}
Services\IShowDialogService.cs
public interface IShowDialogService
{
void ShowPatientWindow();
void ShowOtherWindow();
// ...
}
Services\ShowDialogService.cs
public class ShowDialogService : IShowDialogService
{
public void ShowPatientWindow()
{
var patientWindowViewModel = new PatientWindowViewModel();
var patientWindow = new PatientWindow();
patientWindow.DataContext = patientWindowViewModel;
patientWindow.ShowDialog();
}
public void ShowOtherWindow()
{
// Other window ...
}
}
Finally, you make the connection in the View like this:
MainWindow.xaml
<Window
xmlns:vm="clr-namespace:PatientAdminTool.ViewModel">
<Window.DataContext>
<vm:MainWindowViewModel/>
</Window.DataContext>
<Grid>
<Button Command="{Binding OpenPatientCommand}">Open Patient</Button>
</Grid>
</Window>
Haven't tried it in Visual Studio yet but that's the idea.
If it's the only thing you are going to be displaying in the same window, just put your view in there like any other control:
<Window x:Class="PatientAdminTool.MainWindow"
xmlns:v="clr-namespace:PatientAdminTool.View"... >
<WindowChrome.WindowChrome>
<WindowChrome
CaptionHeight="0"/>
</WindowChrome.WindowChrome>
<v:PatientWindow/>
</Window>
Do you have a root ViewModel for your window? If so, you can bind to a PatientViewModel:
<v:PatientWindow DataContext="{Binding PatientViewModel}"/>
If not, it's common to set the first DataContext to a ViewModel in the code-behind like this:
<v:PatientWindow Name="PatientWindowView"/>
and:
public partial class Window
{
public MainWindow()
{
InitializeComponent();
PatientWindowView.DataContext = new PatientWindowViewModel();
}
}
If you want to display more than one View, use a ContentPresenter like Shakra has answered.
If you want to open a new window, use what Alberto Cardona López has suggested.
I'd like to create a UserControl (in this case a square-Button with defined Backgroundcolors) which can host it's own content.
UserControl:
<UserControl x:Class="SGDB.UI.Controls.ModernButton"
xmlns:local="clr-namespace:SGDB.UI.Controls"
xmlns:converter="clr-namespace:SGDB.UI.Converter"
x:Name="_modernButton">
<Button>
<Button.Resources>
<converter:EnumToColorConverter x:Key="ColorConverter"/>
</Button.Resources>
<Button.Template>
<ControlTemplate>
<Border Width="{Binding Size, ElementName=_modernButton}" Height="{Binding Size, ElementName=_modernButton}" BorderBrush="Black" BorderThickness="0.8,0.8,3,3">
<Grid Background="{Binding BackgroundColor, ElementName=_modernButton, Converter={StaticResource ColorConverter}}">
<ContentPresenter/>
</Grid>
</Border>
</ControlTemplate>
</Button.Template>
</Button>
Now, as you may expect it, if I use this Control inside my MainView everthing works just fine until I define some Content.
Using:
<control:ModernButton Size="200" BackgroundColor="Light">
TEST
</control:ModernButton>
In this case "TEST" will override the whole Content of the UserControl (the whole Button Template). I guess this happens because The Button inside the UserControl is defined as "Content" itself and it will get overridden when defining new Content.
So the final question is: Is it possible to achieve what I'm looking for? if yes: How? How could I "redirect" the Content I'm defining in my MainView into the self-defined ContentPresenter inside my Button Template instead of the UserControls's ContentPresenter?
If possible I don't want to create a new dp-propery which hosts my Content, e.g.:
<controls:MordernButton Size="200" BackgroundColor="Light">
<controls:ModernButton.Content>
I don't want this, if possible
</controls:ModernButton.Content>
</controls:ModernButton>
Use the ContentPropertyAttribute to instruct the xaml to set this property instead of the actual Content property.
[ContentProperty("InnerContent")]
public partial class ModernButton : UserControl
{
public ModernButton()
{
InitializeComponent();
}
public static readonly DependencyProperty InnerContentProperty =
DependencyProperty.Register("InnerContent", typeof(object), typeof(ModernButton));
public object InnerContent
{
get { return (object)GetValue(InnerContentProperty); }
set { SetValue(InnerContentProperty, value); }
}
}
Then in your xaml, Bind the Content Presenter to use InnerContent property instead.
<ContentPresenter Content="{Binding InnerContent, ElementName=_modernButton}"/>
This way you can do the following without replacing the actual content.
<control:ModernButton Size="200" BackgroundColor="Light">
TEST
</control:ModernButton>
Here we go.
<UserControl x:Class="SGDB.UI.Controls.ModernButton"
xmlns:local="clr-namespace:SGDB.UI.Controls"
xmlns:converter="clr-namespace:SGDB.UI.Converter"
x:Name="_modernButton">
<UserControl.Template>
<ControlTemplate TargetType="UserControl">
<Button Content="{TemplateBinding Content}">
<Button.Resources>
<converter:EnumToColorConverter x:Key="ColorConverter"/>
</Button.Resources>
<Button.Template >
<ControlTemplate TargetType="Button">
<Border Width="{Binding Size,
ElementName=_modernButton}"
Height="{Binding Size,
ElementName=_modernButton}"
BorderBrush="Black"
BorderThickness="0.8,0.8,3,3">
<Grid Background="{Binding BackgroundColor, ElementName=_modernButton, Converter={StaticResource ColorConverter}}">
<ContentPresenter />
</Grid>
</Border>
</ControlTemplate>
</Button.Template>
</Button>
</ControlTemplate>
</UserControl.Template>
</UserControl>
Let's assume that youre UserControl is:
<UserControl x:Class="QuickAndDirtyAttempt.Decorator" ....
<UserControl.Template>
<ControlTemplate TargetType="{x:Type local:Decorator}">
<StackPanel Orientation="Vertical">
<Label>Foo</Label>
<ContentPresenter/>
<Label>Bar</Label>
</StackPanel>
</ControlTemplate>
</UserControl.Template>
</UserControl>
Note the TargetType property on the template: without it the project will happily compile, but the ContentPresenter will not work.
And then:
<Window ... >
<StackPanel Orientation="Vertical">
<local:Decorator>
<Label Background="Wheat">User supplied content here</Label>
</local:Decorator>
</StackPanel>
</Window>
I strongly recommend you to read this before implementing anything
Simple; Just circumvent and replace the UserControl's Template.
<UserControl.Template>
<ControlTemplate TargetType="{x:Type UserControl}">
<Button Content="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content}">
<Button.Resources>
<converter:EnumToColorConverter x:Key="ColorConverter"/>
</Button.Resources>
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<Border Width="{Binding Size,
ElementName=_modernButton}"
Height="{Binding Size,
ElementName=_modernButton}"
BorderBrush="Black"
BorderThickness="0.8,0.8,3,3">
<Grid Background="{Binding BackgroundColor, ElementName=_modernButton, Converter={StaticResource ColorConverter}}">
<ContentPresenter />
</Grid>
</Border>
</ControlTemplate>
</Button.Template>
</Button>
</ControlTemplate>
</UserControl.Template>
All a user control is (at least it terms of XAML and its template), is a Border with a ContentPresenter inside it. The ContentPresenter being the only important part, really.
So all you do is gut out its Template and feed the Content property the UserControl has into something a little different; in this case, your button.
This is the difference between making a usercontrol out of other controls, and shoving some controls into a user control.
Making the usercontrol out of other controls gives you much more power.
My example for dialog box
<UserControl
x:Class="CyberpunkModManager.Controls.DialogBox"
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:local="clr-namespace:CyberpunkModManager.Controls"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="450"
d:DesignWidth="800"
Foreground="{StaticResource ThemeForeground}"
mc:Ignorable="d">
<UserControl.Template>
<ControlTemplate TargetType="UserControl">
<Grid Background="{StaticResource ThemeTransparentColor}">
<Border
MinWidth="400"
Padding="12"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Background="{StaticResource ThemeElement}"
CornerRadius="4">
<ContentPresenter />
</Border>
</Grid>
</ControlTemplate>
</UserControl.Template>
I want to use a usercontrol I found on the web in my WPF application. The thing is that I don't want to have to put it in a user control library and build it and then reference that. I just want to be able to import the files into my project and use it from there.
So what I have done is dragged the files into the solution explorer, and it added them okay. I then changed the namespaces to match my own and then attempted to add it to the main forms xaml(This is where my issue is.)
It says the type "local:Pie" is not found. Verify that you are not missing an assembly reference...and you know the rest.
Here is how I am calling it on my main for xaml:
<Grid>
<local:Pie Value="0" x:Name="pieChart" HorizontalAlignment="Center" Width="400" VerticalAlignment="Center" Margin="10"/>
<StackPanel HorizontalAlignment="Left" Margin="30,0,50,0" VerticalAlignment="Center">
<Slider Orientation="Vertical" Minimum="0" Maximum="1" TickFrequency="0.01" Height="272" ValueChanged="Slider_ValueChanged_1" Value="0" Name="slider"/>
</StackPanel>
</Grid>
Here is the controls XAML with my application namespace added:
<UserControl x:Class="MyApplicationNAmespace.Pie"
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" Loaded="UserControl_Loaded_1" SizeChanged="UserControl_SizeChanged_1">
<Grid>
<Ellipse Name="bgCircle"/>
<Path Name="path" StrokeThickness="1.5" Margin="0"/>
<Ellipse Name="hole" RenderTransformOrigin="0.5,0.5">
<Ellipse.RenderTransform>
<ScaleTransform ScaleX="0.45" ScaleY="0.45"/>
</Ellipse.RenderTransform>
</Ellipse>
<Label Content="Value" HorizontalAlignment="Center" VerticalAlignment="Center"
FontFamily="Segoe UI Light" FontSize="38" Name="lblValue"
VerticalContentAlignment="Center" HorizontalContentAlignment="Center"/>
</Grid>
</UserControl>
For the codebehind of the control all I have changed was the namespace to match my projects namespace.
Can anyone tell me what I am doing wrong? Thank you.
I use Caliburn Micro for my WPF application. I implemented a little UserControl:
<UserControl Name="ImageButtonUserControl"
x:Class="SportyMate.Utility.Controls.ImageButton"
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">
<Grid>
<Button>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding ElementName=ImageButtonUserControl, Path=Image}" />
<TextBlock Text="{Binding ElementName=ImageButtonUserControl, Path=Text}" />
</StackPanel>
</Button>
</Grid>
</UserControl>
Now I want to use these Control in my view:
<uc:ImageButton Name="Cancel" Image="/Images/Icons/cancel_16x16.png" Text="Abbrechen" Margin="3" />
When I want to open my view (in my case it's opened as a dialog) it doesn't work. The View does not openend.
When I remove the Name-Attribute everthing is fine, but the Button have no binding to an action. Can anyone tell me what I have to do for a correct binding? A regular Button worked.
You are on a completely wrong way. You shouldn't create a user control for such a simple modification. You need to create a DataTemplate and use it for a Button.ContentTemplate. First you need to define a helper type for button content:
public class ImageButtonContent
{
public BitmapImage Image { get; set; }
public string Label { get; set; }
}
After that you can use it for DataTemplate:
<Window x:Class="Trys.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Trys="clr-namespace:Trys"
Title="MainWindow"
Height="350"
Width="525">
<Window.Resources>
<Trys:ImageButtonContent x:Key="YourImageButtonHere"
Label="Your ImageButtonHere">
<Trys:ImageButtonContent.Image>
<BitmapImage UriSource="your-icon.png" />
</Trys:ImageButtonContent.Image>
</Trys:ImageButtonContent>
<DataTemplate x:Key="ImageButton"
DataType="{x:Type Trys:ImageButtonContent}">
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Image}"
Margin="5" />
<TextBlock Text="{Binding Label}"
VerticalAlignment="Center"
Margin="10,0,0,0" />
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid>
<Button ContentTemplate="{StaticResource ImageButton}"
Content="{StaticResource YourImageButtonHere}"
Height="50"
Width="250" />
</Grid>
</Window>
I used a resource for an object, but you can use a property on your ViewModel. The result is:
And this just a normal button. You can use for it all power of Caliburn.Micro conventions like Click event default binding. Enjoy!