Element binding - c#

<Button x:Name="btn_binding" Content="Binding" HorizontalAlignment="Right" Height="44" Margin="0,127,63,0" VerticalAlignment="Top" Width="67"/>
<TextBox x:Name="txt_binding" Text="{Binding Content,ElementName=btn_binding}" Height="48" Margin="0,48,31,0" TextWrapping="Wrap" VerticalAlignment="Top" HorizontalAlignment="Right" Width="130"/>
it's result will be like this
Then i can get the same result by the below code
public partial class biding : Window
{
public biding()
{
this.InitializeComponent();
txt_binding.Text=btn_binding.Content.ToString();
}
}
please tell me what are the differences of both and i want to which one is best to use...

In first case you bind your TextBox.Text property to Button.Content property and it will be changed everytime the Content is changed. In second you just set Text property once in constructor and changing the Button.Content won't affect into it.
Hope it's clear.

In my point of view... Xaml binding will be reflected in the designer at the time when you typed... No need to wait to run the solution to see the output..
In case of code behind .. you need to run the solution to see the results..

Related

Binding elements to values in WPF

I'm trying to bind a Textbox to a string defined in the .cs file using the followings:
Xaml Code:
<TextBox x:Name="textBox_Data" CaretBrush="DodgerBlue" Foreground="White" Text="{Binding Data}" HorizontalAlignment="Left" Height="22" Margin="10,10,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="123" SelectionChanged="textBox_Data_SelectionChanged"/>
Xaml.cs Code:
public string Data{get; set;}
But the string isn't updating...
Your class has to derive from INotifyPropertyChanged and you have to implement it in your property setter
Or more pleasant way: Install PropertyChanged.Fody from nuget. You can read more about it here: https://github.com/Fody/PropertyChanged
And keep in mind, not to use this.DataContext=this; when initializing your window, use binding as dovid suggests.
{Binding Data} refer the DataContext of current element (or to one of ancestors).
one way
for refer the xaml.xxx.cs you need refer the Window element, you can give him a name:
<Window x:Name="window" x:Class=...
and change the Binding to refer element name:
Text="{Binding Data, ElementName=window}"
Second way
you can also inject all window class to current DataContext:
<Window DataContext="{Binding RelativeSource={RelativeSource Self}}" x:Class=...
Now you can leave the original expression:
Text="{Binding Data}"
Third way
You can also set DataContext from the code. do not change anything in xaml, and add in this line (DataContext = this;) at end of constructor:
public xyz() {
InitializeComponent();
//...
DataContext = this;
}

Issue with displaying images

OK, here's my issue :
I've got a custom class, with a list of items - each of which has an image path associated with it
I've added a folder WITH the images inside the project (so I suppose there are being added in the XAP too, huh?)
When I'm trying to bind the Source of an image item in XAML, it's not working.
<ListBox Margin="0,0,-12,0" ItemsSource="{Binding Items}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="0,0,0,17">
<Image Height="100" Width="100" Margin="12,0,9,0" Source="/AlbumArt/{Binding AlbumArt}"/>
<StackPanel Width="311">
<TextBlock Text="{Binding Title}" TextWrapping="Wrap" Style="{StaticResource PhoneTextLargeStyle}"/>
<TextBlock Text="{Binding Author}" TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
What am I doing wrong? Any ideas?
P.S.
I've also tried Source="{Binding AlbumArt}" but it's still not displaying anything.
The craziest thing is that, if I set the Source to a specific image (e.g. /AlbumArt/someImage.jpg), the image seem to work fine in Visual Studio & the Emulator.
I don't think Binding works that way. If it is not possible to prepend the string "/AlbumArt/" to your image path property (which is AlbumArt), I would suggest using a converter to do so.
Also, formatting strings only works when the target property is a string so StringFormat is out. Someone correct me if I'm wrong about StringFormat
If you have binding issues always check the output window for details. That is where information about binding errors is displayed.
This Source="/AlbumArt/{Binding AlbumArt}" won't work because it will just be treated as a string.
Without seeing your class it's hard to be certain but the property you're binding to ("AlbumArt") should be a Uri and not a string and it should be populated with a relative Uri to the image. That image should also be set to having the build action of Content.
what you have to is this..
<Image Height="100" Width="100" Margin="12,0,9,0" Source="{Binding ImagePath}"/>
as you said you have list of items( i think it would be class that also having paths of images ) so make this property in this class and for every item put the path in this property for coresponding item.
private string _ImagePath;
public string ImagePath
{
get
{
return _ImagePath;
}
set
{
_imagePath = value;
}
}
it would be better if you implement INotifyPropertyChanged in your item class.
How about getting more nesty.
private string _AlbumArt;
public string AlbumArt
{
get
{
return _AlbumArt;
}
set
{
if(_AlbumArt!=null)
_AlbumArt=#"/AlbumArt/"+ value;
}
}
and Binding
<Image Height="100" Width="100" Margin="12,0,9,0" Source="{Binding AlbumArt}"/>
I'm pretty sure you've just used the wrong path, try this one....
"/ApplicationName;component/AlbumArt/{Binding AlbumArt}"
Replace the ApplicationName section with your applications name of course. MAKE SURE TO REPLACE SPACES IN IT WITH %20

How to group together Textblock and Textbox

I am making the UIs for entering master data for various business entities (customer, etc). I run into this need to group together a TextBlock and a TextBox together frequently. i.e.
<Label Content="Civil Status:" Grid.Column="0" Grid.Row="1" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />
<TextBox Grid.Column="1" Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="3" Name="civilStatusTextBox" Text="{Binding Path=CivilStatus, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}" VerticalAlignment="Center" Width="120" />
<Label Content="Company:" Grid.Column="0" Grid.Row="2" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />
<TextBox Grid.Column="1" Grid.Row="2" Height="23" HorizontalAlignment="Left" Margin="3" Name="companyTextBox" Text="{Binding Path=Company, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}" VerticalAlignment="Center" Width="120" />
Is there any way to do this with less typing? i.e.
<custom:LabeledTextBox Label="Civil Status:" Text="{Binding Path=CivilStatus, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}" ... />
Or possibly, any libs which offer something like this?
EDIT : Forget the container Grid for a moment and assume it is a StackPanel.
Here's a step-by-step solution that I managed to put together. To set the stage, I'm going to assume we've got a very simple UserControl that has the following XAML content.
<UserControl x:Class="WpfApplication2.UserControl1" [ ... auto gen code removed ... ] >
<TextBox MinWidth="50" x:Name="TBox" />
</UserControl>
From an XAML that uses our UserControl we'd essentially want to set a data binding for the Text property on TBox. Idealy we could use a plain syntax like:
<local:UserControl1 TBox.Text="{Binding ...}" />
unfortunately I don't know any XAML syntax that would allow targeting an sub-element's property, so the next best thing would be to introduce a "staging" property in the UserControl itself and bind through that.
Since Binding only works for Dependency properties, the property we'll introduce needs to be a DependencyProperty. We'll also bind the Text property of TBox straight to our DependencyProperty from code.
The code-behind for the UserControl looks like this:
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
namespace WpfApplication2
{
/// <summary>
/// Interaction logic for UserControl1.xaml
/// </summary>
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
// Set binding from code
this.TBox.DataContext = this;
this.TBox.SetBinding(TextBox.TextProperty, new Binding { Path = new PropertyPath("TBValue"), Mode = BindingMode.TwoWay, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged });
}
public static readonly DependencyProperty TBValueProperty = DependencyProperty.Register("TBValue", typeof(string), typeof(UserControl1));
public string TBValue
{
get { return this.GetValue(TBValueProperty) as string; }
set { this.SetValue(TBValueProperty, value); }
}
}
}
With this in place we can use the UserControl like this, binding to the TBValue property:
<local:UserControl1 TBValue="{Binding Path=Test, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
What you want to achieve (Master-Detail-Views) is actually well supported by Visual Studio out of the box. Open the following Menu structure : Project -> Add Data Source, then choose data source type Object. In the following, select the classes that you want to generate input fields for and finish the wizard.
Then, if not already open, open up your Data Sources tool window (Shift+Alt+D). You should see a DataSource of the type you just generated. To get a labelled field for each property of the object, open the source dropdown and click Details.
Note that the properties have such dropdowns as well, so that you can choose how you want to edit them (ComboBox, TextBox, Custom, no editor,...).
Now just drag the DataSource onto your window. You will get a Grid that's filled with all the labels and editors you desired. DataBinding and validation is also supported right away, so all you will have to do is set the generated Grid's DataContext.
Hope this saves you some work.
P.S. The screenshots are made in my german VS instance, still I thought they might help you identify the right dialogues / windows.

How to use a xaml object in another class

I have one class with a xaml which contains a label. I want to change content of this label from one different class.
for example i have a class mainwindow.xaml.cs with mainwindow.xaml and i want to handle the label of mainwindow.xaml from the newclass.cs.
How can i do this??
edit: i have this label in a grid and i want to change the content from another class:
<Label Content="" Panel.ZIndex="1" FontWeight="SemiBold" FontSize="16px" Name="lb1" Margin="0,0,0,0" VerticalAlignment="Bottom" Height="30" HorizontalAlignment="Right" Width="250" HorizontalContentAlignment="Right" VerticalContentAlignment="Top"/>
What I would do is something like this, I'm not sure if it's the most logical thing to do but it works for me.
In your newclass.cs :
Class Newclass
{
MainWindow main;
public Newclass(MainWindow win)
{
main = win;
main.label.content = "";
}
}
and then in your mainwindow.xaml.cs:
Newclass class = new Newclass(this);
Data binding and MVVM would be the most elegant solution.
But you can simply use code-behind.
Give the label a name <Label x:Name="myLabel"> so you can access it in your code with that name like any other variable.
You can then pass this variable to your newclass.cs and change its properties there.
you can use binding - or even better binding with MVVM pattern and viewmodel first.
but nevertheless, when asking a question you should post some code

WPF View-ModelView Binding Need Help Please

I have been playing around and looking around on how to Bind a modelview to a view, but i cant seem to work it out.
I have a view called Search and I want to bind it to SearchModelView.
View has one button and one textbox and looks:
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >
<ComboBox Height="23" HorizontalAlignment="Left" Margin="12,40,0,0" Name="comboBox1" VerticalAlignment="Top" Width="174" />
<Label Content="Client:" Height="28" HorizontalAlignment="Left" Margin="0,12,0,0" Name="label1" VerticalAlignment="Top" Width="71" />
<Label Content="Client Reference:" Height="28" HorizontalAlignment="Left" Margin="0,69,0,0" Name="label2" VerticalAlignment="Top" Width="117" />
<TextBox
x:Name="clientRefTxt"
Text="{Binding Path=ClientRef, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}"
Height="23"
HorizontalAlignment="Left"
Margin="12,103,0,0"
VerticalAlignment="Top"
Width="174" />
<Button
Content="Search Debtors"
Height="23"
HorizontalAlignment="Left"
Margin="12,140,0,0"
Name="button1"
VerticalAlignment="Top"
Width="89"
Command="{Binding Path=SearchCommand}"/>
</Grid>
And I want it to bind to SearchViewModel:
namespace Master.ViewModel
{
public class SearchViewModel:WorkspaceViewModel
{
RelayCommand _searchCommand;
readonly Search _search;
#region Search Properties
public string ClientRef
{
get { MessageBox.Show("GET CLIENTREF"); return _search.ClientRef; }
set
{
MessageBox.Show("SET CLIENTREF");
if (value == _search.ClientRef)
return;
_search.ClientRef = value;
base.OnPropertyChanged("ClientRef");
}
}
#endregion
public ICommand SearchCommand
{
get
{
MessageBox.Show("SEARCHCOMMAND");
if (_searchCommand == null)
{
_searchCommand = new RelayCommand(
param=> this.Search(),
param=> this.CanSearch
);
}
return _searchCommand;
}
}
public void Search()
{
MessageBox.Show("SEARCHING");
}
bool CanSearch
{
get { return true; }
}
}
}
I removed all the assemblies at the top but assume that they are all there. Also note that SearchViewModel is in a separate dll, not in the exe with the View.
Any help would be great or at least a pointer in the write direction, I have already read the msdn article on MVVM and that didnt help...I kinda need a better rundown on binding those too pieces.
Thanks in Advance.
P.S.
Some more details:
SearchViewModel belongs to Master.ViewModel
SearchView is part of GUI.View
I have and idea how the binded objects work, im not to sure on how to bind the view to the viewmodel
Is your View a Grid? I've only used UserControl or Window types as Views, but you may have success using a Grid.
Regardless, this is the cleanest way to instantiate the ViewModel with a UserControl View. Just replace the UserControl tags with Grid tags if you're using a Grid.
<UserControl ...(blah blah)
xmlns:viewmodel="clr-namespace:Master.ViewModel">
<UserControl.DataContext>
<viewmodel:SearchViewModel/>
</UserControl.DataContext>
I believe keeping out of the View's code unless necessary is the preferred pattern for MVVM - let the XAML wire things up for you when possible.
You need to set the view's DataContext to an instance of the view model. There are a variety of ways of doing this, including frameworks that wire it up automagically, but the easiest way to get started is to do it in the constructor of the view:
partial class Search : Window
{
public Search()
{
InitializeComponent(); // provided by Visual Studio
DataContext = new SearchViewModel(); // all-important!
}
}
Obviously you may need to provide other information to initialise the SearchViewModel but hopefully this is enough to get you on the right track.
Your will need to bootstrap your application like #itowlson suggests.
But if you have more than one ViewModel you should allow WPF to do it for you. The basic way to do this (which is easy to maintain until you start having more than a dozen views) is to create a DataTemplate to tie the View with your ModelView(which most people call ViewModel).
So the xaml you provided is probably in a UserControl(at least it should be) so you need to do several things
First create a ResourceDictionary
(fast way is to right-click your project and click Add -> Resource Dictionary
In that file(let's name it Resources.xaml) put this :
<DataTemplate DataType="{x:Type vm:SearchViewModel}">
<vw:SearchView>
</DataTemplate>
The above is assuming you put the namespaces vw and vm for View and ViewModel namespaces respectively
Go to your App.xaml and put this:
<Application.Resources>
<ResourceDictionary Source="Resources.xaml"/>
</Application.Resources>
The above will tell WPF that whenever it encounters an object of type SearchViewModel to:
Instantiate a SearchView object
Set it's DataContext to the SearchViewModel object
HTH

Categories