Why is an image resource in a class library not loaded? - c#

I have strange problem, which I don't know how to find - I looked for similair posts here, but failed.
Problem is that I have custom control in WPF and, obviously, I want to reuse it in multiple projects.
I have image background in that control with label over it (assured with Panel.ZIndex).
In one project it is showing correctly, but in another just Label is showing, image for some reason does no display.
What could problem be? I am loosing my mind over this...
Below code of a control:
<UserControl x:Class="SampleControls.LabelWithBoxBackground"
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:SampleControls"
mc:Ignorable="d"
d:DesignHeight="150" d:DesignWidth="400" x:Name="labelWithBoxBackground">
<Grid>
<Image Source="pack://application:,,,/Images/boxImage.png" Stretch="Fill" Panel.ZIndex="1"/>
<TextBlock Background="White" Text="{Binding ElementName=labelWithBoxBackground, Path=Text}" Margin="0,20,0,0" Panel.ZIndex="2" HorizontalAlignment="Center" VerticalAlignment="Center" FontWeight="Bold" FontFamily="Calibri"/>
</Grid>
</UserControl>
Code behind:
public partial class LabelWithBoxBackground : UserControl
{
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(LabelWithBoxBackground), new FrameworkPropertyMetadata(string.Empty));
public string Text
{
get { return GetValue(TextProperty).ToString(); }
set { SetValue(TextProperty, value); }
}
public LabelWithBoxBackground()
{
InitializeComponent();
}
}

Use a full Resource File Pack URI, including the assembly name (not the namespace) of your UserControl library, as shown below.
Otherwise WPF resolves the Pack URI with the name of the "local" assembly, which may be that of the main application.
Source="pack://application:,,,/SampleControls;component/Images/boxImage.png"
Also make sure that the Build Action of the image file is set to Resource.
As a note, setting Panel.ZIndex is pointless here. The elements are stacked by default in the order they are declared in XAML, so the TextBlock is always on top of the Image, even without setting ZIndex.

Related

WPF command bindings in user controls not working

I've tried pretty hard to find a solution by myself searching the web and following examples but everything I've tried until now has failed. I know that my poor experience with WPF is making me missing something huge and silly but as a matter of fact I'm stuck.
As written in the object, I have a custom UserControl that contains a RadioButton. I want to 'expose' the Command of the RadioButton outside through a DependencyProperty of my UserControl.
The .xaml of the UserControl (named 'ImageRadioButton') is the following:
<UserControl x:Class="WpfSinergoHMIControls.Controlli.ImageRadioButton"
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="450" d:DesignWidth="800">
<UserControl.Resources>
</UserControl.Resources>
<Grid>
<Grid>
<RadioButton Command="{Binding SomeCommand, ElementName=me}" Name="button1" Foreground="White">
</RadioButton>
</Grid>
</Grid>
</UserControl>
the dependency property in the UserControl program file is the following:
public static readonly DependencyProperty SomeCommandProperty =
DependencyProperty.Register(
"SomeCommand",
typeof(ICommand),
typeof(ImageRadioButton),
new UIPropertyMetadata(null));
public ICommand SomeCommand
{
get { return (ICommand)GetValue(SomeCommandProperty); }
set { SetValue(SomeCommandProperty, value); }
}
Finally I declare in the application that uses my UserControl an istance:
<Controlli:ImageRadioButton x:Name="btnAutomatic" GroupName="MainMenu" SomeCommand="{Binding DataContext.NavigateAutomaticCommand, ElementName=MainViewObj}" HorizontalAlignment="Left" Height="60" VerticalAlignment="Bottom" Width="140" Canvas.Left="1373" Canvas.Top="5" Margin="6,0,0,5" IsChecked="True"/>
worthless to say that this doesn't work (no command is called). I know that there is something silly that I'm missing but after a lot of trials/searching I still cannot find the solution.
Thanks!
You reference the element me in your command binding, but you do not assign that name anywhere, which means that the binding source (your UserControl) cannot be found at runtime.
Command="{Binding SomeCommand, ElementName=me}"
If you set the name on your UserControl everything works as expected (at least for me).
<UserControl x:Class="WpfSinergoHMIControls.Controlli.ImageRadioButton"
...
x:Name="me">

WPF user control properties not binding or updating

I'm messing around with WPF and creating User Controls but having a hard time understanding how the databinding is supposed to work. Data binding seems to be overly complex and as long as WPF has been out I would think MS would've created some shortcuts to prevent having to do so much boilerplate code.
User control xaml
<UserControl x:Class="WPFTest.FancyBox"
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">
<DockPanel>
<Label Content="{Binding MyText}"></Label>
</DockPanel>
</UserControl>
User control .cs
public partial class FancyBox : UserControl
{
public static readonly DependencyProperty MyTextProperty = DependencyProperty.Register("MyText", typeof(string), typeof(FancyBox), new PropertyMetadata(null));
public string MyText
{
get => (string)GetValue(MyTextProperty);
set => SetValue(MyTextProperty, value);
}
public FancyBox()
{
InitializeComponent();
}
}
Usage in my main window
<StackPanel>
<local:FancyBox MyText="testing!"/>
</StackPanel>
The binding Content="{Binding MyText}" is binding to the DataContext of the control (Label) which is inherited from closest ancestor up the tree who have one (your code doesn't show any DataContext assignment)
Your intended behavior is for Label's Content to bind to the User Control's Property in this case you need to make the user control your source. Many ways to do this for example:
<UserControl x:Class="WPFTest.FancyBox"
x:Name="RootElement"
....
<Label Content="{Binding MyText, Source={x:Reference RootElement} />
Or another way:
<Label Content="{Binding MyText, RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type local:FancyBox}}" />
Keep in mind any Bindings without a source (Source, RelativeSource) will source from DataContext.
I guess I didn't need data binding for this at all
I changed my controls label to:
<Label x:Name="lblText"></Label>
and my code-behind to:
public string MyText
{
get => lblText.Content.ToString();
set => lblText.Content = value;
}

How to change color of all shapes in window with C# and XAML?

Brief
I am trying to programmatically change the colour of specific elements at runtime. The project currently uses Telerik and I am able to change the theme at runtime: This works as expected with no issues. I can't, however, figure out how to change the fill or stroke colour at runtime of custom shape elements in XAML.
Within my project I have a ResourceDictionary file named _Icons.xaml that contains vector shapes to use as the content for other controls (such as buttons).
Code
App.xaml.cs
I am using the following code to change the theme's marker colours at runtime.
GreenPalette.Palette.MarkerColor = (Color)ColorConverter.ConvertFromString("#FF000000");
_Icons.xaml
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MyNamespace">
<ControlTemplate x:Key="Box">
<Viewbox>
<Rectangle Width="357" Height="357" Fill="#000000"/>
</Viewbox>
</ControlTemplate>
<ControlTemplate x:Key="BoxOutline">
<Viewbox>
<Rectangle Width="357" Height="357" StrokeThickness="45" Stroke="#000000"/>
</Viewbox>
</ControlTemplate>
</ResourceDictionary>
MainWindow.xaml
<telerik:RadButton>
<StackPanel>
<ContentControl Template="{StaticResource Box}" Height="58"/>
<TextBlock HorizontalAlignment="Center" Margin="0,5,0,0">Box</TextBlock>
</StackPanel>
</telerik:RadButton>
<telerik:RadButton>
<StackPanel>
<ContentControl Template="{StaticResource BoxOutline}" Height="58"/>
<TextBlock HorizontalAlignment="Center" Margin="0,5,0,0">BoxOutline</TextBlock>
</StackPanel>
</telerik:RadButton>
Question
In _Icons.xaml I have the following lines:
<Rectangle Width="357" Height="357" Fill="#000000"/>
<Rectangle Width="357" Height="357" StrokeThickness="45" Stroke="#000000"/>
Given the following line in App.xaml.cs:
GreenPalette.Palette.MarkerColor = (Color)ColorConverter.ConvertFromString("#FF000000");
How can I either...
Programmatically change the values of Fill and/or Stroke (an element that only has Fill set should only change the Fill value and not add a Stroke attribute) from the App.xaml.cs file? Or ...
Bind the values in XAML for Fill or Stroke to receive the value given by my App.xaml.cs file?
Thank you for taking the time to read my question. Any help regarding this is greatly appreciated.
First i advise you to eject that controls off your resource sheet so you can actually control them properly.
When you do that, go the code behind your control and just use dependency property of type 'Color' of the 'SolidColorBrush' that is used by the background and then bind it by element name, you gotta build the project at least once before attempting to bind.
Here is how you write a dependency property
hint: in VS write 'propdp' and hit tab twice to bring up a template, but you can use mine for now.
public Color _color
{
get { return (Color)GetValue(ColorProperty); }
set { SetValue(ColorProperty, value); }
}
public static readonly DependencyProperty ColorProperty =
DependencyProperty.Register("_color", typeof(Color), typeof(Fileentity), null);
after you build once go to the xalm and put this inside your rectangle:
<Grid.Background>
<SolidColorBrush Color="{Binding
_color,ElementName=YourControlName" />
</Grid.Background>
if you do it right you will be able to access this property when inserting the control on you Page like
<local:YourcontrolName _color="{x:Bind MyColorProperty }"/>
where 'MyColorProperty' is a property that implements INotifyPropertyChanged.
An alternative way is to use a datacontext directly on the usercontrol and just bind your color to one of its properties like:
public YourControl(){
this.InitializeComponent();
this.DataContext = new MyClassDataContext();
var myContext= (MyClassDataContext)this.DataContext;
_color=MyContext.MyColorProperty;}
Where MyClassDataContext is any given class that contains a Color property(MyColorProperty) of your choosing.
You need a Dependency property here as well that binds to your Controls xalm like i showed before.
I know all this is might too hard to grasp at once, thats cause it requires basic knowledge of MvvM.

Create a simple UserControl

i'm trying to create a simple Windows Store App.
I want to reuse some "code" in many pages.
For example i need to reuse someting like this in more than one page..
<StackPanel>
<TextBlock Text="Name"/>
<TextBox x:Name="edtNome"/>
Maybe the best method is using "UserControl"...but i can't realize how!
i've created mine MyUC.xaml
<UserControl
x:Class="Crud.View.MyUC"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Crud.View"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">
<Grid>
<StackPanel>
<TextBlock Text="Name"/>
<TextBox x:Name="edtName"/>
</StackPanel>
But now?
I want to put it in my Page.xaml (and in many other), and access the "edtName" from page.xaml code behind.....
what i have to do?
Something like this
in xaml use a binding path. Add an x:Name for your control. ElementName=me 'me' will be the name given to your control
<TextBox x:Name="edtName" Text="{Binding Path=EditName, ElementName=me, Mode=Default}" ..../>
in that code behind add
public string EditName
{
get { return (string)GetValue(EditNameTextProperty); }
set { SetValue(EditNameTextProperty, value); }
}
public static readonly DependencyProperty EditNameTextProperty =
DependencyProperty.Register("EditName",
typeof(string),
typeof(YourClassNameHereForThisControl),
new FrameworkPropertyMetadata(""));

Binding to UserControl DependencyProperty

I have created a UserControl with some DependencyProperties (in the example here only one string property). When I instantiate the Usercontrol, I can set the property of the UserControl and it is shown as expected. When I am trying to replace the static text by Binding, nothing is displayed.
My UserControl looks as follows:
<User Control x:Class="TestUserControBinding.MyUserControl"
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="30" d:DesignWidth="100">
<Grid>
<Label Content="{Binding MyText}"/>
</Grid>
</UserControl>
The Code Behind is:
namespace TestUserControBinding {
public partial class MyUserControl : UserControl {
public MyUserControl() {
InitializeComponent();
this.DataContext = this;
}
public static readonly DependencyProperty MyTextProperty =
DependencyProperty.Register(
"MyText",
typeof(string),
typeof(MyUserControl));
public string MyText {
get {
return (string)GetValue(MyTextProperty);
}
set {
SetValue(MyTextProperty, value);
}
}// MyText
}
}
When I try this in my MainWindow, everything is as expected:
<Window x:Class="TestUserControBinding.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestUserControBinding"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<local:MyUserControl MyText="Hello World!"/>
</StackPanel>
</Window>
But this doesn't work:
<Window x:Class="TestUserControBinding.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestUserControBinding"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<local:MyUserControl MyText="{Binding Path=Text}"/>
<Label Content="{Binding Path=Text}"/>
</StackPanel>
</Window>
The behaviour of the label is correct, so there is no Problem with the Property "Text"
What is my mistake?
With the following binding in your UserControl:
<Label Content="{Binding MyText}"/>
I'm not sure how setting the text directly to the MyText property works. You must be setting the DataContext on the UserControl somewhere for this to work.
Regardless, this binding is the issue - as I understand your scenario, you don't want to bind to the DataContext of the UserControl because that will not necessarily have a MyText property. You want to bind to the UserControl itself, and specifically the DependencyProperty you created. To do that, you need to use a RelativeSource binding, like the following:
<Label Content="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:MyUserControl}}, Path=MyText}"/>
This will navigate up the visual tree to MyUserControl and then find the MyText property there. It will not be dependent on the DataContext, which will change based on where you place the UserControl.
In this case, local refers to a namespace you'll need to define in the UserControl:
<UserControl x:Class="TestUserControBinding.MyUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestUserControBinding"
...>
And your second example should work at that point.
There is a misunderstanding of how DataContexts are set. This is working against you...
Ultimately the binding to MyText on the user control, is not bound to the control's MyText dependency property but to the page's DataContext and there is no MyText property.
Let me explain
Explanation When the user control is put on your main page, it inherits its controls parent's DataContext (the StackPanel). If the parent's DataContext is not set, it will move up the chain to the StackPanel's parent's DataContext (ad Infinium) until it gets to the page's DataContext (which in your example is set and valid).
When you bind on the main page such as <local:MyUserControl MyText="{Binding Path=Text}"/> it looks for Text property on the main pages DataContext and sets the dependency property MyText to that value. Which is what you expect and it works!
Current State
So the state of the user control in your code is this, its DataContext is bound to the page's DataContext and MyText dependency property is set. But the internal control's binding to MyText fails. Why?
The user control has the parent's data context, and you are asking the control to bind to a MyText property on that data context. There is no such property and it fails.
Resolution
To bind to the control's instance and get the value from MyText property, just put a name (an element name) on the control such as
<User Control x:Class="TestUserControBinding.MyUserControl"
...
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
x:Name="ucMyUserControl"
and then properly path the binding away from the default DataContext and to the elementnamed named instance called ucMyUserControl. Such as:
<Label Content="{Binding MyText, ElementName=ucMyUserControl }"/>
Note that VS2017/2019 will actually intellisense the ElementName after you have named the control.
Side Effect of Just Using The Parents Data Context
A side effect of the original situation without the resolution mentioned, is that you could just bind the user control's binding to Text and it will work because the binding is defaulting to the page's datacontext. Subtle...
<User Control x:Class="TestUserControBinding.MyUserControl"
mc:Ignorable="d"
d:DesignHeight="30" d:DesignWidth="100">
<Grid>
<Label Content="{Binding Text}"/>
That works and technically you could remove the dependency property. If the control is not used outside the project, it could be designed to bind to other named properties with no ill effect as well.
Then all usercontrols could become defacto sub controls of the main page, as if you just pasted the internal XAML onto the page.

Categories