Binding doesn't work with inherited attribute - c#

I've a problem to use binding in a ComboBox.
<ComboBox
Margin="2"
x:Name="itemSelector"
SelectionChanged="itemSelector_SelectionChanged">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Id}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
My object is public class MyButton : MyElement and the Id attribute is set in MyElement class.
Of course Id is a public attribute: public string Id;.
When I try to access a attribute which is in the MyButton class it works but with the "Id" field I got nothing...

You can't bind to a field; you need to make Id a property instead.
Replace your field with public string Id { get; set; }

It should be property (with getter and setter), not field. Because you should notify the UI that the value of the property changed (and you should implement the INotifyPropertyChanged interface)
The code shold look like for C# 5
public string Id
{
get { return _id; }
set { SetProperty(ref _id, value); }
}
private string _id;
or for C# 4
public string Id
{
get { return _id; }
set
{
_id = value;
RaisePropertyChanged(() => Id);
}
}
private DateTime _id;
the full code you can see e.g. in this blog post (both for 4 and 5 version of C# language) http://jesseliberty.com/2012/06/28/c-5making-inotifypropertychanged-easier/
(Beware that the C# 5 requres .Net 4.5, therefore your application will not run on WinXP. C# 4 requires .Net4.0 so it has not this limitation.)

Related

Possible way to reduce translation properties with MVVM in WPF

I'm doing refactoring for our app. We currently have 2 languages supported, where the logic is sitting inside TranslationService, injected through DI container (using Prism if matters) into View models.
In order to bind the translation to the text property there is tons of properties in the view model, e.g.
public string SomeText => _translationService.GetTranslation("someText");
public string AnotherText => _translationService.GetTranslation("notherText");
And the binding is happening as usual
<TextBlock Text="{Binding SomeText}" HorizontalAlignment="Center" />
Is there a way to reduce those properties? For example to bind the Text property to the GetTranslation method with a parameter?
I've seen how to use ObjectDataProvider but this doesn't really help me out, because the method parameters are hard-coded as per my understanding.
You may declare a helper class with a single indexer property like
public class Translation
{
private readonly TranslationService translationService;
public Translation(TranslationService service)
{
translationService = service;
}
public string this[string key]
{
get { return translationService.GetTranslation(key); }
}
}
which would be used as a single property in your view model:
public class ViewModel
{
public ViewModel()
{
Translation = new Translation(_translationService);
}
public Translation Translation { get; }
}
You would bind it like this:
<TextBlock Text="{Binding Translation[someText]}"/>

Model Display Name in Data-Grid as Column

I would like to publish some information in a two-dimension data-grid. First column the name of the attribute, second the current value. Currently I created an array that I attached to the WPF data-grid and filled it upside down with an Attribute = "Username" and a Value = "Waldow". Now I would like to know if there is maybe another way by using a model class where I define every attribute as a string but in the end can display it in the same way, but have a better code.
Let`s say this is my model:
public class InformationModel
{
[Description("Hostname_Description")]
[Display(Name = "Hostname_Display")]
public string Hostname { get; set; }
[Display(Name = "Username_Display")]
public string Username { get; set; }
...... more values
}
Now I want a Datagrid like this:
Hostname | PC0004
Username | Waldow
but by just specifying the value:
<DataGrid x:Name="datagrid_information" ItemsSource="{Binding Information}" IsReadOnly="True" AutoGenerateColumns="False" Margin="11,10,10,0" HorizontalAlignment="Left" VerticalAlignment="Top" SelectionMode="Single" AlternationCount="1">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Display}" Header="Attribute"/>
<DataGridTextColumn Binding="{Binding Description}" Header="Value"/>
</DataGrid.Columns>
</DataGrid>
The model class will not be extended, meaning the entries will always be the same and no more rows will be added.
You should transform your model into a view model that contains a property per column that you want to display in the DataGrid (and bind to an IEnumerable<InformationViewModel>):
public class InformationModel
{
public string Attribute { get; set; }
public string Value { get; set; }
}
You can then set the properties based on the attributes using reflection.
There is no way to retrieve the value of the attributes in XAML though. You can only bind to public properties. It's then up to you as a developer to set these properties.
You might set the Attribute property of the sample class above to the string "Hostname", or to the value of the attribute that you can get using reflection. How the value is set doesn't matter as far as the XAML/UI is concerned.
As suggested I used an own class. So basically in my main class I set a listener on my informationModel and always when a value got changed it will launch the method Model_PropertyChanged. My InformationModel got extended by INotifyPropertyChanged, which calls OnPropertyChanged always when a value got changed:
public MainViewModel() {
// set listener
informationmodel.PropertyChanged += Model_PropertyChanged;
}
private void Model_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
System.Diagnostics.Debug.WriteLine("Property changed: " + e.PropertyName);
// Update object in list
var obj = Informationdgm.FirstOrDefault(x => x.Attribute == informationmodel.GetType().GetProperty(e.PropertyName).GetCustomAttribute<DisplayAttribute>()?.Name.ToString());
if (obj != null)
{
obj.Value = informationmodel.GetType().GetProperty(e.PropertyName).GetValue(informationmodel, null);
}
}

Raising a property change event for class object

I have a class as follows:
public class UserData : INotifyPropertyChnaged
{
public string strUserName;
public string UserName
{
get { return strUserName; }
set { SetProperty(ref strUserName, value); }
}
private string strPhoneNumber;
public string UserPhoneNumber
{
get { return strPhoneNumber; }
set { SetProperty(ref strPhoneNumber, value); }
}
private List<UserMailID> listUserMailID;
public List<UserMailID> ListOfUserMailID
{
get { return listUserMailID; }
set { SetProperty(ref listUserMailID, value); }
}
}
I'm accessing this class at some location and this class object I am binding to my view:
private UserData cActiverUser;
public UserData ActiverUser
{
get { return cActiverUser; }
set { SetProperty(ref cActiverUser , value); }
}
Suppose there is UserName field in my view; my data binding goes like this:
TextBox.Text="{Binding ActiverUser.StrUserName, UpdateSourceTrigger=PropertyChanged}
Binding works well, but I am unable to raise the property changed event when I change this user name field on my view. I have tried setting Mode="TwoWay" also.
In your XAML binding, try setting NotifyOnTargetUpdated=True, or if that doesn't work NotifyOnSourceUpdated=True.
I had the same issue with a project I did a while ago, and it was one of those that got it working.
Also on this line:
public string strUserName;
Should this be private? and you should be specifying the binding as UserName, not strUserName?
I believe the bindings are also case sensitive.
If you're using Prism, derive UserData and whatever class has UserData as its property from BindableBase, which implements INotifyPropertyChanged, but also lets you use SetProperty(...). I'm not even sure how you were able to get it to work before, but I suspect you're not showing us your original code, since you misspelled INotifyPropertyChanged -- INotifyPropertyChnaged.
Additionally, are you actually instantiating the object? Don't forget to do that.
Lastly, you're binding to ActiverUser.StrUserName, but UserData does not have a property StrUserName. It has UserName, which is what you want to bind to.

XAML GridView, ObservableCollection and changing an item's properties

I have a class, derived from BindableBase, which contains two properties:
private string sourceCallNumber;
public string SourceCallNumber
{
get { return sourceCallNumber; }
set { SetProperty(ref sourceCallNumber, value); }
}
private string sourceMediaType;
public string SourceMediaType
{
get { return sourceMediaType; }
set { SetProperty(ref sourceMediaType, value); }
}
I have an ObservableCollection that contains a number of items using that class.
I have a GridView for which I set the ItemsSource to point to the ObservableCollection.
My problem is that if I change the value of, say, SourceMediaType on one of the items, the display does not update. I have put debugging in and can confirm that changing the value causes OnPropertyChanged to fire for that property.
I've read quite a few SO questions and answers around similar problems and I'm getting quite confused as to what I need to do in order to get this to work.
My understanding was that although ObservableCollection itself doesn't do anything when a property is changed, if the item itself triggers an OnPropertyChanged, that should get the display to update.
(There was one answer I read that proposed the use of code provided called TrulyObservableCollection but the problem I've got there is that everything refreshes rather than just the one item that has been updated).
What am I missing or misunderstanding, please?
Thanks.
C# apps should implement INotifyCollectionChanged and System.Collections.IList (not IList Of T).
public class NameList : ObservableCollection<PersonName>
{
public NameList() : base()
{
Add(new PersonName("Willa", "Cather"));
Add(new PersonName("Isak", "Dinesen"));
Add(new PersonName("Victor", "Hugo"));
Add(new PersonName("Jules", "Verne"));
}
}
public class PersonName
{
private string firstName;
private string lastName;
public PersonName(string first, string last)
{
firstName = first;
lastName = last;
}
public string FirstName
{
get { return firstName; }
set { firstName = value; }
}
public string LastName
{
get { return lastName; }
set { lastName = value; }
}
}
Look at GridView.
#RodrigoSilva put me on the correct path ... the XAML that references the values was this:
<StackPanel>
<TextBlock Text="{Binding DisplayCallNumber}" Style="{StaticResource TitleTextBlockStyle}" Visibility="{Binding GotCallNumber, Converter={StaticResource DisplayIfTrue}}" Margin="0,0,0,10"/>
<TextBlock Text="{Binding DisplayMediaType}" Style="{StaticResource ItemTextStyle}" Visibility="{Binding GotMediaType, Converter={StaticResource DisplayIfTrue}}" Margin="0,0,0,10"/>
</StackPanel>
which doesn't directly reference the underlying properties SourceCallNumber and SourceMediaType. As a result, although OnPropertyChanged is correctly firing for SourceCallNumber and SourceMediaType, that isn't causing the display to update because that isn't what the XAML is pointing at.
Explicitly changing the call to SetProperty to this:
SetProperty(ref sourceCallNumber, value, "DisplayCallNumber");
fixes the problem but is not a GOOD fix because some other part of the app may actually be binding to SourceCallNumber and won't get a property update after this change. The GOOD fix is to use a converter as explained in http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh464965.aspx.

Binding to properties does not update the related property

I have on the server side class Person with some properties, one of them is PhoneNumber (this is edmx auto generated - from DB). In the UI I have 2 textboxes, one is prefix, and the other is postfix, so I wanted to extend Person class and make it partial with 2 more properties, prefix and postfix and in the UI bind them to this properties which will update the PhoneNumber property, but somehow, prefix and postfix has value but PhoneNumber does not.
Here is my code:
Server Side:
Public partial class Person : EntityObject
{
//Auto generated from edmx
...
...
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=true)]
[DataMemberAttribute()]
public global::System.String PhoneNumber
{
get
{
return _PhoneNumber;
}
set
{
OnPhoneNumberChanging(value);
ReportPropertyChanging("PhoneNumber");
_PhoneNumber = StructuralObject.SetValidValue(value, true, "PhoneNumber");
ReportPropertyChanged("PhoneNumber");
OnPhoneNumberChanged();
}
}
}
public partial class Person
{
[DataMember]
public string PhoneNumberPrefix
{
get { return PhoneNumber.Substring(0, 3); }
set { PhoneNumber = value + PhoneNumber.Substring(3); }
}
[DataMember]
public string PhoneNumberPostfix
{
get { return PhoneNumber.Substring(3); }
set { PhoneNumber = PhoneNumber.Substring(0, 3) + value; }
}
}
Client Side:
DataContext is the Person.
<TextBox Grid.Column="0" MaxLength="3"
Text="{Binding PhoneNumberPrefix, Mode=TwoWay}" />
<TextBlock Grid.Column="1" Text="-" />
<TextBox Grid.Column="2"
Text="{Binding PhoneNumberPostfix, Mode=TwoWay}" />
Final Result:
After I add values to those textboxes I get the values in Prefix and Postfix but the PhoneNumber is still null. Print screen in debug mode:
I have tried to add UpdateSourceTrigger or Implement INotifyPropertyChanged and no help, can someone help me please?
Thanks in advance !
Instead of PhoneNumber.Substring(0, 3) try this:
PhoneNumber != null ? PhoneNumber.Substring(0, 3) : string.Empty;
Or ask manually if(PhoneNumber != null)...

Categories

Resources