WP8.1 - UserControl Textbox + image, not showing data - c#

I'm most probably missing something obvious as I'm new to WPF development. I'm trying to create a Windows Phone 8.1 application and for my use I want to create a custom user control that contains hero information and hero icon (simple game-related information lookup app).
I have created a usercontrol with name HeroInformationControl and then defined an image and textblock in XAML. Looking up through various resources online I created it as follows:
<UserControl Name="HeroInformationControl"
x:Class="DotaHelper.HeroInformation"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DotaHelper"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="50"
d:DesignWidth="400">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"></ColumnDefinition>
<ColumnDefinition Width="3*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Image
HorizontalAlignment="Left"
Height="Auto"
Stretch="Fill"
VerticalAlignment="Top"
Width="Auto" Source="{Binding ElementName=HeroInformationControl, Path=HeroImage}"
/>
<TextBlock
Grid.ColumnSpan="2"
HorizontalAlignment="Center"
Height="50"
Grid.Column="1"
TextWrapping="Wrap"
Text="{Binding ElementName=HeroInformationControl, Path=HeroName}"
VerticalAlignment="Center"
Width="300"/>
Then, HeroInformation.xaml.cs:
public partial class HeroInformation
{
public HeroInformation()
{
this.InitializeComponent();
this.DataContext = this;
}
public static readonly DependencyProperty HeroNameProperty =
DependencyProperty.Register("HeroName", typeof(string), typeof(string), new PropertyMetadata(""));
public string HeroName
{
get { return (string)GetValue(HeroNameProperty); }
set { SetValue(HeroNameProperty, value); }
}
public static readonly DependencyProperty HeroImageProperty =
DependencyProperty.Register("HeroImage", typeof(string), typeof(string), new PropertyMetadata(""));
public string HeroImage
{
get { return (string)GetValue(HeroImageProperty); }
set { SetValue(HeroImageProperty, value); }
}
}
MainPage.xaml, HeroInformation object:
<local:HeroInformation
x:Name="HeroInformation1"
HorizontalAlignment="Left"
Height="Auto"
VerticalAlignment="Top"
Width="200"
/>
And from the UI thread in MainPage.xaml.cs:
HeroInformation1.HeroImage = hero.IMGurl;
HeroInformation1.HeroName = hero.Heroname;
Sorry for a long code but I have virtually no idea where the problem is.
As a note: hero.IMGUrl and hero.Heroname properties are both of string.
Also if I add to Mainpage.xaml properties by hand (HeroImage and HeroName) it loads.
Any help to understand what's wrong would be appreciated - also, if you spot something that is far from best programming practice I'd be grateful for tips.

Never. Ever. Ever. Do this:
this.DataContext = this;
Instead, give your UserControl an x:Name in your XAML file. Like this:
<UserControl x:Name="usr" ... >
This will allow you to bind to your Dependency Properties using the following binding:
Text="{Binding DataContext.HeroName, ElementName=usr}"
Alternatively, you can bind the UserControl to itself using the following:
DataContext="{Binding RelativeSource={RelativeSource Self}}"
And your binding will look like this:
Text="{Binding HeroName}"
EDIT: Also, as Juan has noticed, your Dependency Property declarations are incorrect:
public string HeroName
{
get { return (string)GetValue(HeroNameProperty); }
set { SetValue(HeroNameProperty, value); }
}
// Using a DependencyProperty as the backing store for HeroName. This enables animation, styling, binding, etc...
public static readonly DependencyProperty HeroNameProperty =
DependencyProperty.Register("HeroName", typeof(string), typeof(HeroInformation), new PropertyMetadata(null));
Pro-tip: Use propdp -> Tab -> Tab to declare a dependency property.

the only thing you missed was:
public static readonly DependencyProperty HeroNameProperty =
DependencyProperty.Register("HeroName", typeof(string), typeof(HeroInformation), new PropertyMetadata(""));
typeof(HeroInformation)
the rest is perfect and the way to do it. Might be the image give some issue (I cannot remember in all platforms (WPF,WP, UWP) if it is right use String for URI.

Related

Using DependencyProperty to Display Placeholder Text on a TextBox (UWP)

I have a custom user control which consists only a TextBox, I want to be able to bing a Placeholder text to that Textbox. My UserControl code is like this
<UserControl
x:Class="Proj.Editors.EditTextControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MemberSuiteConsoleApp.Controls.Editors"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid>
<TextBox x:Name="txtbox" Width="300" PlaceholderText="{Binding ElementName=txtbox, Path=DataContext.PlaceholderText}"></TextBox>
</Grid>
public sealed partial class EditTextControl : UserControl
{
public EditTextControl()
{
this.InitializeComponent();
}
public string PlaceholderText
{
get { return (string)GetValue(PlaceholderTextProperty); }
set { SetValue(PlaceholderTextProperty, value); }
}
// Using a DependencyProperty as the backing store for PlaceholderText. This enables animation, styling, binding, etc...
public static readonly DependencyProperty PlaceholderTextProperty =
DependencyProperty.Register("PlaceholderText", typeof(string), typeof(EditTextControl), new PropertyMetadata(""));
}
And I am trying to use this UserControl in my page like this in my Page
<Grid>
<editors:EditTextControl PlaceholderText="My placeholder" Height="400"></editors:EditTextControl>
</Grid>
But for some reason, Placeholder text is not showing in Textbox, What I am missing here?
You can use x:Bind instead. I tried and works.
<TextBox x:Name="txtbox" Width="300" PlaceholderText="{x:Bind PlaceholderText, Mode=OneWay}"></TextBox>

How to set a WPF usercontrol property from XAML?

I'm trying to set the fill property of several instances of the same usercontrol from XAML in order to distinguish them. I'm using a dependency property in the C# codebehind of the control and referring to that in the XAML when I instantiate the control. Here's a simplified example of what I've tried, first the XAML of the user control:
<UserControl x:Class="RectangleFillUserControlTest.RectangleFillTest"
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="50" d:DesignWidth="150">
<Grid>
<Rectangle x:Name="rect" HorizontalAlignment="Left" Height="50" Stroke="Black" VerticalAlignment="Top" Width="150"/>
</Grid>
</UserControl>
Now the codebehind:
namespace RectangleFillUserControlTest
{
public partial class RectangleFillTest : UserControl
{
SolidColorBrush fillBrush;
public static readonly DependencyProperty FillColourProperty = DependencyProperty.Register
("FillColour", typeof(string), typeof(RectangleFillTest), new PropertyMetadata(string.Empty));
public string FillColour
{
get { return (string)GetValue(FillColourProperty); }
set
{
SetValue(FillColourProperty, value);
if (value == "red") fillBrush = new SolidColorBrush(Colors.Red);
else fillBrush = new SolidColorBrush(Colors.Green);
rect.Fill = fillBrush;
}
}
public RectangleFillTest()
{
InitializeComponent();
}
}
}
I instantiate the control in the main window and try to set the fill colour to red:
<Window x:Class="RectangleFillUserControlTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:RectangleFillUserControlTest"
Title="MainWindow" Height="350" Width="525">
<Grid Background="#FF1D2CC3">
<local:RectangleFillTest FillColour="red"/>
</Grid>
</Window>
But the rectangle remains unfilled, even when I run the project. Can anyone help please?
Cheers,
Tim
There are two things wrong with your dependency property.
First, its type should be Brush, not string, because that is the type used by properties of WPF controls like Shape.Fill or Control.Background. WPF provides automatic type conversion from strings like "Red" or "#FFFF0000" in XAML to type Brush.
Second, you should not have anything else than a call to SetValue in the setter method of the CLR wrapper. The reason is explained in the XAML Loading and Dependency Properties article on MSDN:
Because the current WPF implementation of the XAML processor behavior
for property setting bypasses the wrappers entirely, you should not
put any additional logic into the set definitions of the wrapper for
your custom dependency property. If you put such logic in the set
definition, then the logic will not be executed when the property is
set in XAML rather than in code.
So your dependency property declaration should look like this:
public static readonly DependencyProperty FillBrushProperty =
DependencyProperty.Register(
"FillBrush", typeof(Brush), typeof(RectangleFillTest));
public Brush FillBrush
{
get { return (Brush)GetValue(FillBrushProperty); }
set { SetValue(FillBrushProperty, value); }
}
To react to property changes, you would now register a PropertyChangedCallback with property metadata. But you don't need to do that here, because you could simply bind the property in the UserControl's XAML like this:
<Rectangle Fill="{Binding FillBrush,
RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}}" ... />
I will explain why is is not working and how to solve.
1.- A Dependency Property is only called when the usercontrol has that dependency property in the visual tree.
In case you want to do in that way, you need to add for instance :
new PropertyMetadata(string.Empty, ValueChanged));
and there change the value:
public static readonly DependencyProperty FillColourProperty = DependencyProperty.Register
("FillColour", typeof(string), typeof(RectangleFillTest), new PropertyMetadata(string.Empty, ValueChanged));
private static void ValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = d as RectangleFillTest;
var fillBrush = new SolidColorBrush();
if (control.FillColour == "red")
fillBrush = new SolidColorBrush(Colors.Red);
else
fillBrush = new SolidColorBrush(Colors.Green);
control.rect.Fill = fillBrush;
}
public string FillColour
{
get
{
return (string)GetValue(FillColourProperty);
}
set
{
SetValue(FillColourProperty, value);
}
}
That is explicit for your logic, in case you need a more generic code for any color, etc using binding the property to the rectangle, just tell me.
You need to bind your Dependency Property to the Fill property of your Rectangle in the xaml of your UserControl. You'll have Something like this :
<Rectangle x:Name="rect" Fill="{Binding FillColour, RelativeSource={RelativeSource FindAncestor, AncestorType=RectangleFillTest}}" HorizontalAlignment="Left" Height="50" Stroke="Black" VerticalAlignment="Top" Width="150"/>
Also, in your dependency property, it's type should be Brush, and not String.

WPF: binding to properties from class with custom behavior

using WPF, c#, VS 2012
Try to implement some custom behaviors for UI with WPF.
Currently create class that inherited from Behavior<FrameworkElement>
Idea: create one area on UI for entering name (I used textBox) - another area (Rectangle) - press and see some action with data from prev field.
What was done:
Class for implementing idea (class with Behavior)
class SayHello: Behavior<FrameworkElement>
{
public string Words { get; set; }
protected override void OnAttached()
{
AssociatedObject.MouseLeftButtonUp += OnMouseClick;
}
private void OnMouseClick(object sender,
System.Windows.Input.MouseButtonEventArgs e)
{
MessageBox.Show(string.Format("hello , {0}", Words));
}
protected override void OnDetaching()
{
AssociatedObject.MouseLeftButtonUp -= OnMouseClick;
}
}
XAML:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
xmlns:local="clr-namespace:CH08.MovingCircle"
x:Class="CH08.MovingCircle.MainWindow"
Title="MainWindow" Height="350" Width="525">
<Canvas>
<Border Canvas.Top="220" BorderBrush="Black"
BorderThickness="2">
<TextBox x:Name="_enteredWords" Width="200"/>
</Border>
<Rectangle Stroke="Blue" Canvas.Top="250" Fill="Aquamarine"
Width="200" Height="50">
<i:Interaction.Behaviors>
<local:SayHello
Words="{Binding Text, ElementName=_enteredWords}"/>
</i:Interaction.Behaviors>
</Rectangle>
</Canvas>
Got error : A 'Binding' cannot be set on the 'Words' property of type 'SayHello'. A 'Binding' can only be set on a DependencyProperty of a DependencyObject...
If i change part of XAML to
<Rectangle Stroke="Blue" Canvas.Top="250" Fill="Aquamarine"
Width="200" Height="50">
<i:Interaction.Behaviors>
<local:SayHello
Words="Adbracadabra"/>
</i:Interaction.Behaviors>
</Rectangle>
all works (mean just remove binding).
Question: are it's possible to create binding to properties for class with custom behavior? If yes, how can i do this?
EDIT:
As was suggested by vfabre - changed property to dependency property
public string Words
{
get { return (string)GetValue(WordsProperty); }
set { SetValue(WordsProperty, value); }
}
// Using a DependencyProperty as the backing store for Words.
//This enables animation, styling, binding, etc...
public static DependencyProperty WordsProperty =
DependencyProperty.Register("Words", typeof(string),
typeof(SayHello), new PropertyMetadata(default(string)));
Result
Maybe the error message give us the solution. You have to convert your Words property to a dependency propery the following is an example:
public string Words
{
get { return (string)GetValue(WordsProperty); }
set { SetValue(WordsProperty, value); }
}
// Using a DependencyProperty as the backing store for Words. This enables animation, styling, binding, etc...
public static readonly DependencyProperty WordsProperty =
DependencyProperty.Register("Words", typeof(string), typeof(SayHello), new PropertyMetadata(default(string)));
//public string Words { get; set; }
I recommend you to use the code snnipet propdp. Tipping propdp and then tab+tab.
Here you can find more information about dependency properties.
Regards
Edit
Changed the default value from string.

WPF Usercontrol with custom properties

I want to outsource two images to a custom usercontrol, which should have two properties to be set, one for the source of each image.
But I ran into trouble with the datacontext, which isnt recognised correctly. It might also be a problem, that its the first time that I use dependency properties. Anyway, I hope you can figure out my thoughts and help me here, here comes the sourcecode:
MainViewModel:
public class MainWindowViewModel : INotifyPropertyChanged
{
private string _spielerL1;
private string _spielerL2;
public MainWindowViewModel()
{
SpielerL1 = System.IO.Directory.GetCurrentDirectory() + #"\Images\queen_of_clubs.png";
SpielerL2 = System.IO.Directory.GetCurrentDirectory() + #"\Images\queen_of_diamonds.png";
[...]
}
public string SpielerL1
{
get { return _spielerL1; }
private set
{
_spielerL1 = value;
OnPropertyChanged("SpielerL1");
}
}
public string SpielerL2
{
get { return _spielerL2; }
private set
{
_spielerL2 = value;
OnPropertyChanged("SpielerL2");
}
}
}
In my mainwindow view I am only instantiating the viewmodel and using the control with SourceLeft="{Binding SpielerL1}" and SourceRight="{Binding SpielerL2}"...
My control code behind looks like this (deleted sourceright to make it shorter):
public partial class HandControl
{
public HandControl()
{
InitializeComponent();
DataContext = this;
}
public string SourceLeft
{
get
{
return (string) GetValue(SourceLeftProperty);
}
set
{
SetValue(SourceLeftProperty, value);
}
}
public static readonly DependencyProperty SourceLeftProperty = DependencyProperty.Register("SourceLeft", typeof(string), typeof(HandControl), new PropertyMetadata(""));
}
And finally my usercontrol xaml, which isnt recognising the datacontext or atleast not showing my images:
<UserControl x:Class="FoolMe.Gui.Controls.HandControl"
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">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="3*" />
</Grid.ColumnDefinitions>
<Image Grid.Column="1"
Source="{Binding SourceLeft}" />
<Image Grid.Row="0"
Grid.Column="0"
Grid.ColumnSpan="2"
Source="{Binding SourceRight}" />
</Grid>
</UserControl>
Since I havent done much with WPF and usercontrols yet, I have no clue, whats wrong. Without the usercontrol it has working fine, but outsourcing it like this, my window keeps "white".
Anyone got an idea, what went wrong?
You shouldn't set the DataContext of the UserControl to itself. However, your real problem comes from your Binding on the Image elements. You should use a RelativeSource Binding instead:
<Image Grid.Column="1" Source="{Binding SourceLeft, RelativeSource={RelativeSource
AncestorType={x:Type YourXmlNamespacePrefix:HandControl}}}" />
<Image Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Source="{Binding SourceRight,
RelativeSource={RelativeSource AncestorType={x:Type YourXmlNamespacePrefix:
HandControl}}}" />

Custom usercontrol property binding failure silverlight

I have a custom usercontrol with DataContext="{Binding RelativeSource={RelativeSource self}}"
On the code behind i've made a dependency property like:
public static DependencyProperty ElementNameProperty = DependencyProperty.Register("ElementName",
typeof(string),
typeof(ElementControl),
new PropertyMetadata(new PropertyChangedCallback((s, e) => { new Base().OnPropertyChanged("ElementName"); })));
public string ElementName
{
get
{
return (string)base.GetValue(ElementNameProperty);
}
set
{
base.SetValue(ElementNameProperty, value);
}
}
Now when I try to use this usercontrol in my mainpage.xaml and use the following binding: <test.TestControl ElementName="{Binding name}" />, it keeps searching for 'name' property in my custom usercontrol instead of where it should come from?
What am I doing wrong ?
It searches there because you have the DataContext set on the topmost level for your user control. What you would need to do is get rid of the relative binding to self in the user control and specify ElementName in bindings (inside user control). Btw you probably don't need OnPropertyChanged in the PropertyChangedCallback cause DependencyProperties in their nature notify about value changes.
I eventually solved it this way. Not the way I wanted, but it's a (in my eyes) pretty neat solution.
CustomUserControl.xaml
<UserControl x:Class="TestApp.Controls.CustomUserControl"
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"
mc:Ignorable="d"
Width="75"
Height="75">
<Canvas x:Name="LayoutRoot"
Background="Black">
<StackPanel Orientation="Vertical">
<Image x:Name="UCImage"
Width="50"
Height="50"
HorizontalAlignment="Center" />
<TextBlock x:Name="UCText"
HorizontalAlignment="Center" />
</StackPanel>
</Canvas>
</UserControl>
CustomUserControl.xaml.cs
public partial class ElementControl : UserControl
{
#region DependencyProperty ElementNameProperty
public static DependencyProperty ElementNameProperty = DependencyProperty.Register("ElementName",
typeof(string),
typeof(ElementControl),
new PropertyMetadata(new PropertyChangedCallback((s, e) =>
{
//See Here
((ElementControl)s).UCText.Text = e.NewValue as string;
})));
public string ElementName
{
get
{
return (string)base.GetValue(ElementNameProperty);
}
set
{
base.SetValue(ElementNameProperty, value);
}
}
#endregion
}

Categories

Resources