|
Check the output window of the debugger for a binding error. Without the entire context of what you are doing I would guess the problem is the binding of the textblock. Inside the data template, the data context is the current row of the data set repeated for each item in the set.
So if you had a data context for the page which had a collection of categories and a collection of objects which had a category and a name, your combobox source is correct and will bind to the collection of categories. However, the selected value will bind to <row>.Category.Id where row is an object in the collection holding the rows withing the data context. Your bindings should be relative to that.
If your row contains a "category" object, your bindings are correct and the problem is likely that you aren't raising PropertyChanged for the Name property when you are changing the Id property.
If I could see the class that is your DataContext I could be more specific.
HTH
|
|
|
|
|
Funny, I just answered another question with this same suggestion. I am not seeing a binding path error of any sort.
The DataContext does have a category object and that object has an ID and a name.
So how do I implement the INPC for this scenario? I realize I could create a public category "SelectedCategory" and bind it to the SelectedItem of the ComboBox and then raise the OnPropertyChanged event when it changes, but what do I need to do in order to update the category name property of the SelectedItem of the ListView? Do I need to raise the OnPropertyChanged("SelectedItem") or what?
|
|
|
|
|
Assuming that your category object has members like "Id", "Name", "Description", etc I'm guessing that you want to change the Id via the combobox and have the rest of the properties follow suit. There are a couple of ways of doing it but knowing that it all starts with the property setter for Id is the key.
When the user selects an item in the combobox, it sets the SelectedItem property to the value or object you have specified. If it is a binding (as in your case) the setter gets called for that property. A normal setter, as you know, usually looks like:
set
{
if(_internalVar != value)
{
_internalVar = value;
RaisePropertyChange("PropertyName");
}
}
That works fine and raising property change there notifies any controls bound to that property that there is a change in it they should grab. But it doesn't do anything else. Even if you added a SelectedCategory property and bound that to the combobox then exposed name and ID through the internal variable, you still wouldn't fire the property change on the name property when the whole object was changed. That is because the binding system just isn't that smart. It must be told there is a change.
So you have a few options...
- If the combobox changes the ID, then in the setter for the ID property, change the name property as well. If you do it like Name = newValue then prop change gets raised in the setter for Name. If you use the internal variable like _name = newValue then you must follow that up by explicitly raising propertychanged passing Name as the property that has changed.
- You could expose just an ID property and in the setter call a method that sets the values on the category object. Again, if you use the public property setters you will get the event raised. If you use the internal versions, you must raise the event.
If you breakpoint on the Id property setter, property getter, and the same for the Name property, you will see how those things get called. (Basically setter followed by the getter in response to the event) To get the Name to update on the control, that PropertyChanged event needs to be raised carrying "Name" as the property name. How you get there is up to you.
Unfortunately, debugging bindings isn't always the easiest thing... in fact it can be pretty infuriating. A lot of times I'll break on those property setter/getter and start working backwards to figure out why something isn't working. And don't discount typos either. I can't tell you how many times a stupid typo when raising propertychanged or in a binding has wasted hours of my time.
|
|
|
|
|
Thank you, I failed to implement the INPC at the model level, so none of the screen elements were updating as intended. I am still not getting the dropdown to update correctly, though. How should I implement that combobox?
I tried binding the Combobox directly to the Category like this:
<ComboBox ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}},Path=DataContext.Categories}" DisplayMemberPath="Category" SelectedValuePath="Id" SelectedItem="{Binding Category}" Style="{StaticResource GridEditStyle}" />
But when I do that the textblock updates correctly but there is no item selected initially when I click on the field to edit it.
Here are the important model pieces:
private SCategory category;
public SCategory Category
{
get { return category; }
set
{
if (category == value)
return;
category = value;
OnPropertyChanged("Category");
}
}
And then the SCategory:
public class SCategory : Base
{
private int id;
public int Id
{
get
{
return id;
}
set
{
if (value == id)
return;
id = value;
OnPropertyChanged("Id");
OnPropertyChanged("Category");
}
}
private string category;
public string Category
{
get
{
return category;
}
set
{
if (string.IsNullOrEmpty(value) || value == category)
return;
category = value;
OnPropertyChanged("Category");
}
}
}
If I bind the combobox using SelectedValuePath and SelectedValue I am not getting the right field in the textblock, but I am getting the correct field in the combobox.
Cheers, --EA
|
|
|
|
|
Instead of
public SCategory Category
{
get { return category; }
set
{
if (category == value)
return;
category = value;
OnPropertyChanged("Category");
}
}
Make it this:
public SCategory Category
{
get { return category; }
set
{
if (category == value)
return;
category.Id = value.Id;
category.Category = value.Category;
OnPropertyChanged("Category");
}
}
By doing that you will invoke PropertyChange on the Id and Category properties and items bound to those properties should get the event and refresh their values.
Also, you have a bad naming convention by calling your derived class Category and a property of the base class Category. That won't do you any favors when you are trying to unwind the bindings and class relationships. You might want to rename the class... maybe CategoryClass or CategoryObject.
HTH
- Jason
|
|
|
|
|
The naming convention is not as bad as it looks, I just had to make some changes to post it due to proprietary information disclosure and such.
There is still something I am missing here. After setting that in the type class (Which contains the Category class) the setter is not getting hit again.
If I bind the combobox using SelectedValuePath and SelectedValue={Binding Category.Id} the setter property is hit within the Category class on the Id property. However, if I bind the combobox using SelectedItem={Binding Category, Mode=TwoWay} I do not get a display in the combobox and the setter is not getting hit on the Type object Category property.
I am going to need stronger meds if I spend too much more time in WPF land I think.
|
|
|
|
|
Just out of curiosity... is the Category property not null when the initial binding occurs? Meaning you set the Category property the combobox is bound against to an instance of your class either at the declaration of the backing variable or in the datacontext constructor?
There is an annoying "feature" that if you try to bind to a property that exposes an object and that object is null when the binding occurs, then eventing doesn't work. For example, if you bind a combobox itemsource to a collection that is initially null, even if you set the property to a fully-populated collection later, the combobox will not pickup the change. There has to be an instance of the class exposing the PropertyChanged event at the time of the binding for it to work. Especially helpful in these cases is that there are no errors. Raising the property changed event just goes nowhere.
|
|
|
|
|
I flattened the model due to some database design problems that I can't (not allowed to) fix. As such I am exposing the categoryId and categoryName property on the type object. I can use most of the same framework, the question is how do I cleanly update the categoryName when the Id is updated?
I could put a lookup into the PropertyChanged event of the categoryId, but it seems dirty to have to visit the database from the model object. Seems dirty, thoughts?
|
|
|
|
|
Sorry for the delay getting back...
I understand your concerns. You didn't say that you are using MVVM but since you are talking about a model class I'm guessing you are, in fact, using it. If that is the case, you should put all of your database code in the model. The idea of the model is to hide the details of the backing data store so you could switch it out if you needed. So it may feel dirty but that is exactly what you are supposed to be doing.
I have fallen into a pattern where I usually create two classes for data. I'll call them DataObject and DataModel (really xxxxObject and xxxxModel as appropriate). DataObject represents the actual data and is typically nothing more than a class with a bunch of public properties. I usually inherit INotifyPropertyChanged and INotifyDataError on that class so that it can alert to value changes and it can alert to bad values.
The second class, DataModel, is where I put the data access functions. This class is data source specific and usually implements an interface I have specified with the functions I'll need. In your case, this class might expose a function like:
public CategoryBase GetCategoryById(int Id)
which would obviously return a category based on an Id. In your ViewModel you would have a property which would take a category ID and in the setter you would call the GetCategoryById then use the results to set the category and Id on the property exposing that data object. As long as the underlying DataObject implements INPC and you have bound to a non-null category object at startup, then the category and Id should follow along with changes in the Id sourced from the combobox.
The grid complicates things a bit because you have a collection of the data objects but that is pretty easy to work around. If you are uncomfortable wiring it up from the property setter for the Id property, remember that Combobox exposes a selection changed event. You could bind a command to that and use that as a jump point to call the DB fetch method and set the category data object.
Ultimately though... I suggest you take MVVM as a suggestion and not a set of hard and fast rules. Like a lot of stuff in software development, there is always some scenario that doesn't fit the rules so we end up breaking them to make it work. If you figure out a system that works, then consider it a success. Just document the code so the next guy can see why you did what you did and why you broke the rule.
|
|
|
|
|
Yes, it is MVVM, I should have mentioned as much. My project is laid out as described, Business Object, Data Access Layer. The business object is responsible for retrieving the data from the database and transforming it into classes suitable for the View and ViewModel. The VM has not interaction with the DAL, just the Business Layer.
That is where the dirtiness comes in, it comes from the fact that the model class would have to interact with the database where currently it is the business object that handles that. It isn't the end of the world, though. If I have the model call the business layer to retrieve the name, I won't feel so bad. Thank you for all your help.
There is no strict adherence to the MVVM pattern here, more of a loose guideline, I just want to make sure that if we change our DAL we have one place to look (BizLayer) to figure out what needs to be changed.
Pipedream, I am sure.
Cheers, --EA
|
|
|
|
|
I facilitated the loading of my window height and width of my Border I named BorderSplash.
animation works fine but the problem is that it does not stop what I want to avoid.
<Storyboard x:Key="AnimGrossirImage" >
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Width" Storyboard.TargetName="BorderSplash">
<EasingDoubleKeyFrame KeyTime="0" Value="5"></EasingDoubleKeyFrame>
<EasingDoubleKeyFrame KeyTime="0:0:3" Value="300" ></EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Height" Storyboard.TargetName="BorderSplash" AutoReverse="False">
<EasingDoubleKeyFrame KeyTime="0" Value="5" ></EasingDoubleKeyFrame>
<EasingDoubleKeyFrame KeyTime="0:0:0.7" Value="300" ></EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
Thank you in advance for your help!
|
|
|
|
|
Member 10016140 wrote: but the problem is that it does not stop what I want to avoid.
When you want to stop the animation ?
are there fixed triggers that you can use?
you can use BeginStoryBoard and StopStoryBoard with Triggers.
Read this[^] and this.[^]
don't worry and don't get frustrated. everything will eventually sort out and then we will regret being frustrated. the only thing that matters is conscious efforts to make things right. - Rahul Rajat Singh
Just that something can be done, doesn't mean it should be done. Respect developers and their efforts! - Jyothikarthik_N
modified 21-Jan-14 4:56am.
|
|
|
|
|
I have a listbox with checkbobxes in it:
<ListBox Grid.Row="1"
ItemsSource="{Binding EmployeesInDept}"
Style="{StaticResource ListBoxStyle}"
Margin="5">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsChecked}"
IsEnabled="{Binding DataContext.AllowChangeEmpIsChecked, RelativeSource={RelativeSource AncestorType=TrainingTemplateEditorView}}"
Margin="0,0,3,0"/>
<TextBlock Text="{Binding EmployeeName}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The list is bound to a collection of EmployeeSummaryEntity, which has an IsChecked property on it.
I have a property on my viewmodel called AllowChangeEmpIsChecked. I want to enabled/disable ALL the checkboxes in the list when other conditions in the VM are true but it's not working. Anyone see what I'm doing wrong?
Thanks
If it's not broken, fix it until it is
|
|
|
|
|
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsChecked}"
IsEnabled="{Binding DataContext.AllowChangeEmpIsChecked, RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"
Margin="0,0,3,0"/>
<TextBlock Text="{Binding EmployeeName}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
I think the issue is with the RelativeSource property of the binding.
"As beings of finite lifespan, our contributions to the sum of human knowledge is one of the greatest endeavors we can undertake and one of the defining characteristics of humanity itself"
modified 23-Jan-14 1:14am.
|
|
|
|
|
A couple things:
1. Are you sure that it is not disabled? Stupid disabled checkboxes still look enabled often times unless you specifically change the style of a disabled checkbox.
2. Are you sure that your binding path is resolving correctly? Make sure you are not getting a "blah not found on object blah" error in output.
You can try handling this with a style trigger as well.
<Style x:TargetType="CheckBox">
<Style.Triggers>
<DataTrigger Binding="Your correct path here">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
Something like that anyways.
Cheers, --EA
|
|
|
|
|
Hi everybody,
I just installed vs2013 and I carried a WPF project, previous developed with VS2010, under this environment. Happens to me a very strange thing that obviously does not happen with 2010 .... I have my own custom control that defines a runtime URI to a dictionary ... the strangeness lies in the fact that in the code of xaml page when i define the use of my control, i've got the error reported in subject... but the strangest thing is that if i start the dubug, everything works fine and the style is correctly applied .... someone has an idea?
the code look like that :
the custom control
using System;
using System.Windows.Controls;
using System.Windows;
using System.ComponentModel;
using System.Windows.Data;
namespace myListView
{
public class myListView : ListView
{
protected override void OnInitialized(EventArgs e)
{
Uri uri = new Uri("Skins\\myDictionary.xaml", UriKind.Relative);
dictionary = Application.LoadComponent(uri) as ResourceDictionary;
base.OnInitialized(e);
}
}
}
the xaml page
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:xlw="clr-namespace:myListView;assembly=myListView"
Title="MainWindow" Height="350" Width="525">
<Grid>
<xlw:myListView>
<!-- the editor tell me that can t find the Skins/myDictionary.xaml -->
</xlw:myListView>
</Grid>
</Window>
P.S. The custom control is an external dll included in Reference...it's one of my several generic object that i use in several solution
modified 10-Jan-14 6:04am.
|
|
|
|
|
I find that the xaml design interface regularly fails when dealing with custom controls and particularly complex layouts, this is not new to 2013.
Never underestimate the power of human stupidity
RAH
|
|
|
|
|
thank you for your reply...but have you ever find a workaround ? i can't believe that i can't migrate my project to the new platform....
|
|
|
|
|
You mean a new version!
I believe is is probably a bug in VS where is the xaml is too complex and it fails to render it. As irritating as it is I have never bothered to try and resolve the issue as it rarely happens and the resolution would probably take too much time anyway.
I now try and keep a views complexity down
Never underestimate the power of human stupidity
RAH
|
|
|
|
|
i don't think it's a complexity problem....i add a simple example in my first post where i've got the problem...
|
|
|
|
|
As Mycroft has stated it's a XAML designer issue. The same bug is in VS2012.
"As beings of finite lifespan, our contributions to the sum of human knowledge is one of the greatest endeavors we can undertake and one of the defining characteristics of humanity itself"
|
|
|
|
|
Unbelivable ! I'll try to send the bug report to Microsoft tech support...
|
|
|
|
|
I am trying to create a UI where I can move objects around. At the same time I need to be able to interact with the objects.
I am following this example[^].
I have looked at this many times before, and it get confusing, but I do understand some of it.
So far I have this:
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="..\AppResources.xaml"/>
</ResourceDictionary.MergedDictionaries>
<!-- MoveThumb Template -->
<ControlTemplate x:Key="MoveThumbTemplate" TargetType="{x:Type classes:MoveThumb}">
<Rectangle Fill="Transparent"/>
</ControlTemplate>
<!-- ResizeDecorator Template -->
<ControlTemplate x:Key="ResizeDecoratorTemplate" TargetType="{x:Type Control}">
<Grid>
<classes:ResizeThumb Height="3" Cursor="SizeNS" Margin="0 -4 0 0" VerticalAlignment="Top" HorizontalAlignment="Stretch"/>
<classes:ResizeThumb Width="3" Cursor="SizeWE" Margin="-4 0 0 0" VerticalAlignment="Stretch" HorizontalAlignment="Left"/>
<classes:ResizeThumb Width="3" Cursor="SizeWE" Margin="0 0 -4 0" VerticalAlignment="Stretch" HorizontalAlignment="Right"/>
<classes:ResizeThumb Height="3" Cursor="SizeNS" Margin="0 0 0 -4" VerticalAlignment="Bottom" HorizontalAlignment="Stretch"/>
<classes:ResizeThumb Width="7" Height="7" Cursor="SizeNWSE" Margin="-6 -6 0 0" VerticalAlignment="Top" HorizontalAlignment="Left"/>
<classes:ResizeThumb Width="7" Height="7" Cursor="SizeNESW" Margin="0 -6 -6 0" VerticalAlignment="Top" HorizontalAlignment="Right"/>
<classes:ResizeThumb Width="7" Height="7" Cursor="SizeNESW" Margin="-6 0 0 -6" VerticalAlignment="Bottom" HorizontalAlignment="Left"/>
<classes:ResizeThumb Width="7" Height="7" Cursor="SizeNWSE" Margin="0 0 -6 -6" VerticalAlignment="Bottom" HorizontalAlignment="Right"/>
</Grid>
</ControlTemplate>
<!-- Designer Item Template-->
<ControlTemplate x:Key="DesignerItemTemplate" TargetType="ContentControl">
<Grid DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}">
<classes:MoveThumb Template="{StaticResource MoveThumbTemplate}" Cursor="SizeAll"/>
<Control Template="{StaticResource ResizeDecoratorTemplate}"/>
<ContentPresenter Content="{TemplateBinding ContentControl.Content}"/>
</Grid>
</ControlTemplate>
</ResourceDictionary>
</Window.Resources>
<Canvas Grid.Row="2"
Grid.Column="0"
Background="Transparent">
<ContentControl Name="DesignerItem"
Width="100"
Height="100"
Canvas.Top="100"
Canvas.Left="100"
Template="{StaticResource DesignerItemTemplate}">
<TextBox Grid.Row="1"
IsHitTestVisible="False"
Text="This is some text"
Height="Auto">
</TextBox>
</ContentControl>
</Canvas>
When I run it, I see Resize handles on all 4 corners of the textbox, and I can click & drag. The problem is that I cannot edit the text in the text box because the IsHitTestVisible property on the textbox Is False.
Set IsHitTestVisible = true and you can no longer drag & resize.
What I'd like is to be able to both drag/drop AND edit.
Can anyone help?
Thanks
If it's not broken, fix it until it is
|
|
|
|
|
You are trying to implement something like this; WPF Surface Panel[^]
"As beings of finite lifespan, our contributions to the sum of human knowledge is one of the greatest endeavors we can undertake and one of the defining characteristics of humanity itself"
|
|
|
|
|
wow i am fighting with this for 2 days now !
i am displaying the result of this linq query in a wpf datagrid
var v = from p in _context.EXAMENS_VALEURs
join b in _context.EXAMENS_TYPES_VALEURs on p.EXV_ID_VALEUR_TYPE equals b.ID_EXAMEN_TYPE_VALEUR
join c in _context.EXAMENS_TYPES_GROUPEs on b.EXTV_ID_GROUPE equals c.ID_EXAMEN_TYPE_GROUPE
select new ValeursResult()
{
ID = p.ID_EXAMEN_VALEUR,
Designation = b.EXTV_DESIGNATION,
Groupe = c.EXTG_DESIGNATION,
Valeur = p.EXV_VALEUR
};
((CollectionViewSource)this.FindResource("ExamensView")).Source = v.ToList();
the ValeursResult type is declared like this
public class ValeursResult
{
public int ID { get; set; }
public string Groupe { get; set; }
public string Designation { get; set; }
public string Valeur { get; set; }
}
the datagris id bound to the collectionviewdource with this
<DataGrid x:Name="grd2" AutoGenerateColumns="True"
ItemsSource="{Binding Source={StaticResource ExamensView}}" />
now i can view the result in my datagrid, i can change the values in the cells ,
but the update is not done on the server with
_context.Savechanges()
i have also tried this line of code just before calling savechanges
((ListCollectionView)((CollectionViewSource)this.FindResource("ExamensView")).View).CommitEdit();
but again the databse table is never updated
btw i am using telerik orm with a firebid database
thanks for your help
|
|
|
|