|
I have a datagrid where I have two buttons on each row - one for moving a row up and one for moving a row down.
Each button has a command for allowing the user to move the selected row in either direction. The problem that I am facing is that it not working. I think the problem that I may have is that the other controls (combo boxes) on the rows are bound to data sources through the MVVM model where I am manipulating the rows on the code behind of the XAML thinking this would be the logical place in which to do it.
The code I have for one of the buttons is below:
private void MoveRowDown(object sender, ExecutedRoutedEventArgs e)
{
int currentRowIndex = dg1.ItemContainerGenerator.IndexFromContainer(dg1.ItemContainerGenerator.ContainerFromItem(dg1.SelectedItem));
if (currentRowIndex >= 0)
{
this.GetRow(currentRowIndex + 1).IsSelected = true;
}
}
private DataGridRow GetRow(int index)
{
DataGridRow row = (DataGridRow)dg1.ItemContainerGenerator.ContainerFromIndex(index);
if (row == null)
{
dg1.UpdateLayout();
dg1.ScrollIntoView(selectedAttributes.Items[index]);
row = (DataGridRow)dg1.ItemContainerGenerator.ContainerFromIndex(index);
}
return row;
}
|
|
|
|
|
Instead of working with the grid you should work with the data. Add a sort field to the class used to populate the grid and manipulate the order in the VM.
Never underestimate the power of human stupidity
RAH
|
|
|
|
|
I want to populate a TreeView dynamically during runtime of my program.
The WPF TreeView is for me very confusing and I can't really find any easy and simple guide. I hence this thread will be long because I have lot's of questions. Let's take them one by one.
My XAML is just:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<TreeView Name="tvTree"></TreeView>
</Grid>
</Window>
My C# code is:
namespace WpfApplication1
{
public partial class MainWindow : Window
{
List<Person> persons;
public MainWindow()
{
InitializeComponent();
persons = new List<Person>();
persons.Add(new Person("Person1"));
persons.Add(new Person("Person2"));
persons.Add(new Person("Person3"));
persons.Add(new Person("Person4"));
persons.Add(new Person("Person5"));
tvTree.ItemsSource = persons;
}
}
public class Person
{
string name;
public Person(string name)
{
this.name = name;
}
public string Name
{
get { return name; }
}
}
}
This will actually populate the TreeView with five TreeViewItems:
WpfApplication1.Person
WpfApplication1.Person
WpfApplication1.Person
WpfApplication1.Person
WpfApplication1.Person
This was somewhat expected since the TreeView read the ToString() method from my Person class.
But can I make the TreeView read the person's name from the Name property instead? I don't want to override the ToString() method to do this. I would like to use the Name property and connect that property to the XAML code.
|
|
|
|
|
In order to use the TreeView simply in WPF, it's important to understand that a tree represents a hierarchy of information. Another important concept to remember is that you are going to represent the hierarchy by changing the template of the control to display the data in a different fashion. I've deliberately used those words because the thing I want you to remember is that you can change the appearance of data using a DataTemplate , and that as you have a hierarchy of data in the TreeView , it takes a HierarchicalDataTemplate (even though you are only using one level of data, it has to cater for multiple levels).
So, we have a HierarchicalDataTemplate - how do we actually code this in our XAML? Well, we need to apply this to the template for each item (or the ItemTemplate ), so you would add something in that represented a single item. In this case, let's use a TextBlock . This would look like:
<TextBlock Text="{Binding Name}" /> That's all we need to do to actually bind to the name, but where do we put this? Well, we know that we need to add it into a HierarchicalDataTemplate , so let's add that into our TreeView . It looks like this:
<TreeView Name="tvTree">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:Person}">
<Grid>
<TextBlock Text="{Binding Name}" />
</Grid>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView> Now, you might be wondering why we put a DataType against the HierarchicalDataTemplate . Well, as it's a DataTemplate and there may be multiple different types of data under the tree nodes, the DataType tells WPF which particular type of data to render this TreeView out against. This allows you to build an incredibly complex hierarchy of data in the TreeView , and yet have small self-contained DataTemplate elements reshaping the data easily (don't forget to add a namespace reference so that it knows where to pick Person up from).
I hope this helps.
|
|
|
|
|
I know what the TreeView can do in WPF, I just don't know how to do it. So I start very simple and continue on that.
Thanks by the way for the code, it did the trick when I found out how to make a XAML-namespace reference
xmlns:local="clr-namespace:TreeView"
Notice I have change my namespace from WpfApplication1 to TreeView
Now I want to implement the TreeView to add sub TreeViewItems for some of the already existing TreeViewItems. I have changed my C# to:
namespace TreeView
{
public partial class MainWindow : Window
{
List<Person> persons;
public MainWindow()
{
InitializeComponent();
persons = new List<Person>();
Person p1 = new Person("Person1");
p1.Children.Add(new Person("Children1"));
p1.Children.Add(new Person("Children2"));
persons.Add(p1);
persons.Add(new Person("Person2"));
Person p3 = new Person("Person3");
p3.Children.Add(new Person("Children1"));
persons.Add(p3);
persons.Add(new Person("Person4"));
persons.Add(new Person("Person5"));
tvTree.ItemsSource = persons;
}
}
public class Person
{
List<Person> children = new List<Person>();
string name;
public Person(string name)
{
this.name = name;
}
public string Name
{
get { return name; }
}
public List<Person> Children
{
get { return children; }
set { children = value; }
}
}
}
As expected no XAML code is written to handle the Children list so no sub TreeItemView is visible. How shall I implement that in my XAML code?
|
|
|
|
|
This one's going to appear a little bit magic right now. If you add ItemsSource="{BindingChildren}" to your HierarchicalDataTemplate definition, you'll automatically get the children added into the correct location. This turns your TreeView into this:
<TreeView Name="tvTree">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate
ItemsSource="{Binding Children}"
DataType="{x:Type local:Person}">
<Grid>
<TextBlock Text="{Binding Name}" />
</Grid>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
|
|
|
|
|
I cannot understand how that XAML code works but it sure does Even with several multiple levels of children. Kick ass!
Thanks a lot! I will try to implement this into a more complex system of classes where the data is stored in.
|
|
|
|
|
You are welcome. The key is actually the DataType, the ItemsSource tells it where to get the data, and in the case of the top level elements it fails to find that item, so it falls back to the default ItemsSource (the one specified against the TreeView).
|
|
|
|
|
I have one further problem concerning displaying items in the TreeView. Adding one more collection for each Person, the Item collection.
The entire C# code is:
namespace TreeView
{
public partial class MainWindow : Window
{
List<Person> persons;
public MainWindow()
{
InitializeComponent();
persons = new List<Person>();
Person p1 = new Person("Person1");
Person c1 = new Person("Children1");
c1.Items.Add(new Item("Telephone"));
c1.Items.Add(new Item("Game console"));
p1.Children.Add(c1);
p1.Children.Add(new Person("Children2"));
p1.Items.Add(new Item("Car"));
p1.Items.Add(new Item("Computer"));
persons.Add(p1);
tvTree.ItemsSource = persons;
}
}
public class Person
{
List<Person> children = new List<Person>();
List<Item> items = new List<Item>();
string name;
public Person(string name)
{
this.name = name;
}
public string Name
{
get { return name; }
}
public List<Person> Children
{
get { return children; }
set { children = value; }
}
public List<Item> Items
{
get { return items; }
set { items = value; }
}
}
public class Item
{
string type;
public Item(string type)
{
this.type = type;
}
public string Type
{
get { return type; }
}
}
}
Notice the List<item> collection in the Person class. Can I display that collection in the TreeView at the same time as the List<person> Children collection?
How should I implement that in my XAML code?
My current XAML code:
<Window x:Class="TreeView.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TreeView"
Title="MainWindow" Height="350" Width="525">
<Grid>
<TreeView Name="tvTree" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="5,5,0,0" Width="300" Height="300">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}" DataType="{x:Type local:Person}">
<Grid>
<TextBlock Text="{Binding Name}" />
</Grid>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Grid>
</Window>
The result should be something like this:
Person1
Chilrden1
Telephone
Game console
Chilrden2
Car
Computer
modified on Monday, July 4, 2011 7:20 AM
|
|
|
|
|
Hello,
I am using WCF + Silverlight. Can anyone can tell me how to make sync call to WCF methods?
Thanks in Advance..
|
|
|
|
|
You can't make a synchronous call from Silverlight to WCF. Silverlight demands that the calls are made asynchronously because it runs on the browser UI thread, so you could end up blocking the browser if you made a long running synchronous call.
Right - that's the official party line out the way. In reality, you can make synchronous calls, you just can't use the WCF RIA features to do it. My good friend and one of the brightest human beings to walk the planet, Daniel Vaughan, came up with a fascinating method to do just this. You can find details on how to do this here[^].
|
|
|
|
|
hi
I my SL4 app i created an usercontrol and i'm showing it in a page.
This usercontrol has some button(created dinamically) and a public property named "SelectedValue" (that change when a button is clicked and its value is Button.Tag).
I want to notify the page (somehow, through event) that the "SelectedValue" is changed. How can i???
"For as long as men massacre animals, they will kill each other. Indeed, he who sows the seed of murder and pain cannot reap joy and love." Pythagoras
|
|
|
|
|
jadughar wrote: I want to notify the page (somehow, through event) that the "SelectedValue" is changed. How can i???
You can add an event to your usercontrol class which is raised when the property is changed. The page can subscribe to this event. For example:
public event EventHandler<EventArgs> SelectedValueChanged;
object _selectedValue;
public object SelectedValue
{
get { return _selectedValue; }
set
{
if (_selectedValue != value)
{
_selectedValue = value;
EventHandler<EventArgs> evnt = SelectedValueChanged;
if (evnt != null)
evnt(this, new EventArgs());
}
}
}
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Hi Mark
Thanks for the answer!!! It work fine !!
I tried with similar code but it didn't work. I would like to post my code and want to know what was wrong.
Anyway your sample is awesome!!!
thanks again
bye
"For as long as men massacre animals, they will kill each other. Indeed, he who sows the seed of murder and pain cannot reap joy and love." Pythagoras
|
|
|
|
|
jadughar wrote: I would like to post my code and want to know what was wrong.
Go ahead!
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
this was the code giving error :
public event RoutedEventHandler SomethingHappened;
int progressivoSelezionato = 0;
public int valoreSelezionato
{
get { return this.progressivoSelezionato; }
set
{
this.progressivoSelezionato = value;
RoutedEventHandler myHandler = SomethingHappened;
if (myHandler != null)
myHandler(this, new RoutedEventArgs());
}
}
"For as long as men massacre animals, they will kill each other. Indeed, he who sows the seed of murder and pain cannot reap joy and love." Pythagoras
|
|
|
|
|
It's not a routed event so I wouldn't use RoutedEventHandler.
Still I would think it would work but I could be wrong - didn't try it
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
hi Mark
I didn't understand ur last post.
Anyway ur sample is working perfectly.
My sample is giving error.
Anyway what's the difference between RoutedEvent and the Event(that u used in ur sample) ??
"For as long as men massacre animals, they will kill each other. Indeed, he who sows the seed of murder and pain cannot reap joy and love." Pythagoras
|
|
|
|
|
jadughar wrote: My sample is giving error.
At compile time or runtime? I would think that should work too, and it compiles.
jadughar wrote: what's the difference between RoutedEvent and the Event(that u used in ur sample) ??
Routed events are a WPF/Silverlight thing: "A routed event is an event that is potentially passed on (routed) from a child object to each of its successive parent objects in the object tree." The only real difference I saw with your code is you used a RoutedEvent delegate which takes a different eventargs parameter than a simple C# event, which is what I used.
See Events Overview for Silverlight[^]
I only meant I wouldn't use RoutedEvent because RoutedEvents get routed by the framework and that may cause confusion in your code if it's not really an event that gets routed.
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
i was getting error at run time, no errors while compile time ..
"For as long as men massacre animals, they will kill each other. Indeed, he who sows the seed of murder and pain cannot reap joy and love." Pythagoras
|
|
|
|
|
jadughar wrote: i was getting error at run time, no errors while compile time ..
I'm not going to test it to see the actual error message, but regardless, a RoutedEvent was not what you needed. Just a .NET event.
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Ok
thanks for the answer !!!
bye
"For as long as men massacre animals, they will kill each other. Indeed, he who sows the seed of murder and pain cannot reap joy and love." Pythagoras
|
|
|
|
|
I have a DP that I registered as BindsTwoWayByDefault. This works fine if I bind it to property in the VM, but if I bind it to something in the XAML, then it gives me the exception 'Two-way binding requires Path or XPath error'.
if I do:
{Binding SomeProperty}
it works fine, but if I do:
{Binding ElementName=filenameColumn}
then I get that exception. Is there something else I need to do to get the first method to be 2 way by default and the second way to not throw an exception.
I think some of the .NET properties behave that way, in that they are 2 way on the first method, but don't puke on the second method.
I have another DP thats an enum and it doesn't have this issue (I can bind to a property in the VM as well as hard code the enum type in a string), just when the DP type is a class. I register them both the same exact way.
|
|
|
|
|
The issue you are seeing here is that the binding doesn't know what it has to bind to, so if you did {Binding Path=., ElementName=filenameColumn} it should work. Basically, ElementName is not a path so it cannot be used like this, it has nothing to do with whether or not the binding is 2 way.
|
|
|
|
|
Originally the DP was 1-way, so it didn't have this issue and both methods worked fine.
{Binding ElementName=filenameColumn}
This binding DOES work fine (when the DP is one way). The DP was correctly set to filenameColumn. This method:
{Binding SomePropertyInVM}
worked fine as well. Well, sort of. The 2nd method didn't update the property in the VM which is why I made it 2-way. If I change the property back to 1-way, then both methods work again (except for the fact that the 2nd method doesn't update the property in the VM).
What I was saying in my original post was that I don't have this issue with another similiar DP that I changed to 2-way as well. Except that type is a ListViewSortDirection enum and this DP is a GridViewColumn.
So on the other DP, I can do:
TheDP="Ascending" AND TheDP="{Binding SomePropInTheVM}"
if I bind to the prop in the VM, it works fine as 2 way. I guess the first method here isn't using binding, so it doesn't have that issue.
I did try adding a Path=. to the binding as you suggested and it does fix the problem, but I dunno which one is uglier lol:
Having to do this for hard coding in the XAML:
{Binding ElementName=filenameColumn, Path=.}
vs having to do this for MVVM:
{Binding SomePropInTheVM, Mode=TwoWay}
|
|
|
|