Simple popup dialog in WPF (overlay inside Window) - c#

I'm working on a modal dialog popup (I'm not sure about the exact UX term) that is displayed inline, inside of a control or window with darkened background.
Visual example
What I tried is putting a <ContentPresenter /> inside the XAML of the popup and then just instantiate it like this:
<local:Popup Grid.RowSpan="2">
<TextBlock Text="Popup test..." />
</local:Popup>
However, the XAML replaces the entire Popup XAML instead of being placed where the ContentPresenter is.
Q: How is the ContentPresenter here used properly?
Popup.xaml
<ContentControl
x:Class="[...].Popup"
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:[...]"
mc:Ignorable="d" d:DesignWidth="300" d:DesignHeight="300">
<Grid Background="#7f000000">
<Grid Background="White" HorizontalAlignment="Center" VerticalAlignment="Center">
<StackPanel Margin="20">
<TextBlock Text="{Binding Title, RelativeSource={RelativeSource AncestorType=UserControl}}" FontSize="20" />
<ContentPresenter />
</StackPanel>
</Grid>
</Grid>
</ContentControl>
Popup.xaml.cs
using System.Windows;
namespace [...]
{
public partial class Popup : ContentControlBase
{
public static DependencyProperty TitleProperty = DependencyProperty.Register(nameof(Title), typeof(string), typeof(Popup));
public string Title
{
get
{
return (string)GetValue(TitleProperty);
}
set
{
SetValue(TitleProperty, value);
}
}
public Popup()
{
InitializeComponent();
}
}
}

The content of your Popup should be defined as a ControlTemplate for the ContentPresenter to work as expected here. Please refer to the following sample code.
Popup.xaml:
<ContentControl
x:Class="WpfApplication1.Popup"
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:DesignWidth="300" d:DesignHeight="300"
x:Name="popup">
<ContentControl.Template>
<ControlTemplate TargetType="local:Popup">
<Grid Background="#7f000000">
<Grid Background="White" HorizontalAlignment="Center" VerticalAlignment="Center">
<StackPanel Margin="20">
<TextBlock Text="{Binding Title, ElementName=popup}" FontSize="20" />
<ContentPresenter />
</StackPanel>
</Grid>
</Grid>
</ControlTemplate>
</ContentControl.Template>
Popup1.xaml.cs.
public partial class Popup : ContentControl
{
public static DependencyProperty TitleProperty = DependencyProperty.Register(nameof(Title), typeof(string), typeof(Popup));
public string Title
{
get
{
return (string)GetValue(TitleProperty);
}
set
{
SetValue(TitleProperty, value);
}
}
public Popup()
{
InitializeComponent();
}
}
}
Window1.xaml:
<local:Popup Title="Title...">
<TextBlock>Text...</TextBlock>
</local:Popup>

Related

WPF XAML Binding Not Picking Up DependencyProperty Value

I have a really simple UserControl
<UserControl x:Class="Namespace.Views.TabViews.TabViewTemplate"
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="900" d:DesignWidth="880"
d:DataContext="{d:DesignData Type=TabViewTemplate}">
<UserControl.Template>
<ControlTemplate TargetType="UserControl">
<Grid Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Border Grid.Row="0" BorderBrush="#FFB31B16" BorderThickness="0,0,0,1" Margin="20" VerticalAlignment="Top">
<TextBlock VerticalAlignment="Bottom" FontSize="20" LineHeight="24" Margin="0,0,0,5" Text="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=Title}"/>
</Border>
<Border Grid.Row="1" Padding="20">
<ContentPresenter ContentSource="Content"/>
</Border>
</Grid>
</ControlTemplate>
</UserControl.Template>
</UserControl>
and it's code behind
using System;
using System.Windows;
using System.Windows.Markup;
namespace Namespace.Views.TabViews {
/// <summary>
/// Interaction logic for TabViewTemplate.xaml
/// </summary>
[ContentProperty("Content")]
public partial class TabViewTemplate {
public static readonly DependencyProperty TitleProperty =
DependencyProperty.Register("Title", typeof(string), typeof(TabViewTemplate),
new FrameworkPropertyMetadata(
"Sample",
FrameworkPropertyMetadataOptions.AffectsRender,
OnTitleChanged)
);
private static void OnTitleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
var control = d as TabViewTemplate;
if (control != null) control.Title = (string)e.NewValue;
}
public TabViewTemplate() {
InitializeComponent();
}
public static void SetTitle(TabViewTemplate element, string value) {
element.SetValue(TitleProperty, value);
}
public static string GetTitle(TabViewTemplate element) {
return (string) element.GetValue(TitleProperty);
}
public string Title
{
get { return (string)GetValue(TitleProperty); }
set { SetValue(TitleProperty, value); }
}
}
}
I make use of that code like this
<UserControl x:Class="Namespace.Views.TabViews.WelcomeTabView"
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:gif="http://wpfanimatedgif.codeplex.com"
xmlns:tabViews="clr-namespace:Namespace.Views.TabViews"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<tabViews:TabViewTemplate Title="Welcome">
<Grid>
<Border BorderBrush="Coral" BorderThickness="2" Margin="0">
<Image gif:ImageBehavior.AnimatedSource="../../Resources/js_cfg_install_howto.gif"/>
</Border>
</Grid>
</tabViews:TabViewTemplate>
</UserControl>
However the value "Welcome" gets set via the property -- I see this via a breakpoint on the property setter -- however the get is never called. I have used all sorts of Binding combinations, none of which work. What is the "correct" way to set the TextBlock Text by way of a DependencyProperty? Thanks!
It was working. My TextBlock needed a Foreground of Black in order to see the text.

WPF data binding through UserControls

I would like to bind property from the main window's DataContext, above you can see my UserControls and models. So I want to bind the Model.ID.Label1 and Model.ID.Label2 properties to the main_id/card_1/top and main_id/card_1/bottom controls. I hope it's clear. If I enable the
ref_lbl Label it will shows the "lbl1", the card_2 still working with the hardcoded texts but the card_1 will be blank. What should I modify to fix the binding on card_1?
I have an ID UserControl and it contains another UserControl.
XAML:
<UserControl x:Class="stack.ID"
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:Controls="clr-namespace:stack.Controls"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<Label Name="ref_lbl" Grid.Row="0" Content="{Binding Label1}" Visibility="Collapsed" />
<Controls:Card x:Name="card_1" Grid.Row="0" TopLabel="{Binding Label1}" BottomLabel="{Binding Label2}" />
<Controls:Card x:Name="card_2" Grid.Row="1" TopLabel="Text 1" BottomLabel="Text 2" />
</Grid>
Code Behind: default, auto generated
Here is the Card UserControl.
XAML:
<UserControl x:Class="stack.Controls.Card"
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}}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<Label Grid.Row="0" FontSize="20" Foreground="Black" HorizontalAlignment="Center" VerticalAlignment="Center" Content="{Binding TopLabel}" />
<Label Grid.Row="1" FontSize="20" Foreground="Black" HorizontalAlignment="Center" VerticalAlignment="Center" Content="{Binding BottomLabel}" />
</Grid>
Code Behind:
namespace stack.Controls
{
public partial class Card : UserControl
{
public static readonly DependencyProperty TopLabelProperty = DependencyProperty.Register("TopLabel", typeof(string), typeof(Card), new PropertyMetadata(default(string)));
public static readonly DependencyProperty BottomLabelProperty = DependencyProperty.Register("BottomLabel", typeof(string), typeof(Card), new PropertyMetadata(default(string)));
public Card()
{
InitializeComponent();
}
public string TopLabel
{
get
{
return (string)GetValue(TopLabelProperty);
}
set
{
SetValue(TopLabelProperty, value);
}
}
public string BottomLabel
{
get
{
return (string)GetValue(BottomLabelProperty);
}
set
{
SetValue(BottomLabelProperty, value);
}
}
}
}
And here is my main window.
XAML:
<Window x:Class="stack.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:stack"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:Model />
</Window.DataContext>
<Grid>
<local:ID x:Name="main_id" DataContext="{Binding ID}" />
</Grid>
Code Behind: default, auto generated
And I also have 2 models.
namespace stack
{
public class IDModel
{
private string label1 = "lbl1";
private string label2 = "lbl2";
public string Label1
{
get
{
return label1;
}
set
{
label1 = value;
}
}
public string Label2
{
get
{
return label2;
}
set
{
label2 = value;
}
}
}
public class Model
{
private IDModel id = new IDModel();
public IDModel ID
{
get
{
return id;
}
set
{
id = value;
}
}
}
}
Remove
DataContext="{Binding RelativeSource={RelativeSource Self}}"
from the Card's XAML.
It prevents inheriting the DataContext from its parent ID control, which is necessary when you write
<Controls:Card ... TopLabel="{Binding Label1}" />
Instead write the Content bindings in Card's XAML like this:
<Label ... Content="{Binding TopLabel,
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}}" />

WPF CustomControl stops showing up 50% of the time

I have a custom control in my WPF project, I've defined the style, the class, and I've called it in my xaml and made sure to include a reference. when I start the project 50% of the time the custom object renders perfectly, the other 50% it just doesn't show up, but is still interactable.
public class PermissionBox : Control
{
public PermissionBox()
{
DefaultStyleKey = typeof(PermissionBox);
}
public string PumpID
{
get
{
return (string)GetValue(PumpIDProperty);
}
set
{
SetValue(PumpIDProperty, value);
}
}
public static readonly DependencyProperty PumpIDProperty =
DependencyProperty.Register("PumpID", typeof(string), typeof(PermissionBox), new PropertyMetadata(string.Empty));
public string FuelType
{
get
{
return (string)GetValue(FuelTypeProperty);
}
set
{
SetValue(FuelTypeProperty, value);
}
}
public static readonly DependencyProperty FuelTypeProperty =
DependencyProperty.Register("FuelType", typeof(string), typeof(PermissionBox), new PropertyMetadata(string.Empty));
}
in Themes/Generic.xaml
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:POS">
<Style TargetType="{x:Type controls:PermissionBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type controls:PermissionBox}">
<Grid Background="Gray" Opacity="0.8">
<TextBlock Foreground="Black" FontSize="15" Text="Pump ID:" HorizontalAlignment="Left"/>
<TextBlock Foreground="Black" FontSize="15" Text="{TemplateBinding PumpID}" HorizontalAlignment="Right"/>
<TextBlock Foreground="Black" FontSize="15" Text="Fuel Type:" HorizontalAlignment="Left"/>
<TextBlock Foreground="Black" FontSize="15" Text="{TemplateBinding FuelType}" HorizontalAlignment="Right"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
and the calling window
<Window x:Class="POS.Window1"
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:controls="clr-namespace:POS"
mc:Ignorable="d"
Title="Window1" Height="300" Width="300">
<Grid>
<controls:PermissionBox PumpID="100" FuelType="Unleaded"> </controls:PermissionBox>
</Grid>
</Window>
Really appreciate any help with resolving this.

Get property value WPF

I am trying get a value from a property but isn't working I always get a null value.
string imageNormal;
public static readonly DependencyProperty ImageNormalProperty =
DependencyProperty.Register("ImageNormal", typeof(string), typeof(MainWindow));
public string ImageNormal
{
get { return (string)GetValue(ImageNormalProperty); }
set { SetValue(ImageNormalProperty, value); }
}
public ButtonImageStyle()
{
InitializeComponent();
DataContext = this;
Console.WriteLine("Path: " + ImageNormal);
}
Xaml ButtonImageStyle.xaml:
<Image Source="{Binding ImageNormal}" Stretch="None" HorizontalAlignment="Center" VerticalAlignment="Center" />
Xaml MainWindow.xaml:
<local:ButtonImageStyle HorizontalAlignment="Left" Height="60" VerticalAlignment="Top" Width="88" ImageNormal="C:/Users/Xafi/Desktop/add.png"/>
I always obtain next output:
Path:
since your ImageSource is have to be binded to it's parent DependencyProperty (which is defined to your code behind), you have to define your binding to be rlative to your UserControl (let's name it This). Thus please try to change your xaml in the next way:
Xaml code
<UserControl x:Class="SomeBindingExampleSOHelpAttempt.ButtonImageStyle"
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" x:Name="This">
<Grid>
<Image Source="{Binding ElementName=This, Path=ImageNormal, UpdateSourceTrigger=PropertyChanged}"
Stretch="None" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid></UserControl>
Here you can find an additional perfect answer.
Regards.

User control with custom properties

I'm trying to create a UserControl which is a legend of a graph item,
I've defined it so it has a label with the graph name, a check box which
define whether we show it or not and a rectangle with the graph color.
The xaml is defined like this:
<UserControl x:Class="Resources.LegendItem"
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">
<UserControl.Template>
<ControlTemplate>
<StackPanel Margin="1,0,0,0" Orientation="Horizontal">
<CheckBox Name="cb" IsChecked="{TemplateBinding IsGraphVisible}" >
<StackPanel Margin="1,0,0,0" Orientation="Horizontal">
<Rectangle Name="rec" RadiusX="2" RadiusY="2" Height="10" Width="10" />
<Label Name="lab" Content="{TemplateBinding GraphName}" />
</StackPanel>
</CheckBox>
</StackPanel>
</ControlTemplate>
</UserControl.Template>
</UserControl>
and the cs file is:
namespace Resources
{
public partial class LegendItem : UserControl
{
public static readonly DependencyProperty IsGraphVisibleProperty = DependencyProperty.Register("IsGraphVisible", typeof(Boolean), typeof(LegendItem));
public static readonly DependencyProperty GraphNameProperty = DependencyProperty.Register("GraphName", typeof(String), typeof(LegendItem));
public bool IsGraphVisible
{
get { return (bool)GetValue(IsGraphVisibleProperty); }
set { SetValue(IsGraphVisibleProperty, value); }
}
public string GraphName
{
get { return (string)GetValue(GraphNameProperty); }
set { SetValue(GraphNameProperty, value); }
}
public LegendItem()
{
InitializeComponent();
}
}
}
But when I compile it, I get an error "Cannot find the static member 'IsGraphVisibleProperty' on the type 'Control'."
Any help would be appreciated.
You do not need a template at all. UserControl allows the XAML to be declared directly. You can't set the template in a UserControl:
<UserControl x:Class="Resources.LegendItem" x:Name="MyControl"
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">
<StackPanel Margin="1,0,0,0" Orientation="Horizontal">
<CheckBox Name="cb" IsChecked="{Binding ElementName=MyControl, Path=IsGraphVisible}" >
<StackPanel Margin="1,0,0,0" Orientation="Horizontal">
<Rectangle Name="rec" RadiusX="2" RadiusY="2" Height="10" Width="10" />
<Label Name="lab" Content="{Binding ElementName=MyControl, Path=GraphName}" />
</StackPanel>
</CheckBox>
</StackPanel>
</UserControl>
You need to specify TargetType="{x:Type Resources.LegendItem}" on your ControlTemplate, otherwise it defaults to being a template for Control and you get that error.

Categories