|
Creating derived types for controls in WPF is usually a bad idea. Have you heard of DataTemplates or DataTemplateSelectors? You can use the former when you want to use a template according the the type of data (e.g., you can display class Cat differently than class Duck) and you can use the latter to select the template based on custom logic (e.g., if the name of the animal is "Alfred" or the previous animal was a Duck and the current one is a Dog, then display a particular template). I suggest you read Dr. WPF's Take on Data Templates.
|
|
|
|
|
I'm looking for information on a more specific issue than your largely unrelated response seems to recognize.
Yes, I am familar with templating, template seletors and what they can/cannot do. The article linked in the original posting and the specific issue of implementing routed command handlers within the individual treeviewitems illuminate the primary issue that I am trying to address. If you have suggestions on effective techniques to solve that sort of issue, your input will be warmly received.
With respect to blandly identifying good or bad approaches for UI development within WPF, I recommend that you review the "Control Authoring Overview" in MSDN. It specificially highlights when to write a new control and the capabities and limitations imposed by the level within the class heirarchy one chooses to base there development.
|
|
|
|
|
I can be more specific if you can be more specific. Here are some questions you can answer that may lead to more specific answers for you.
hb52134214 wrote: this approach does not allow handling routed commands or creating command bindings
Sure it does. Why wouldn't it? What are you trying to accomplish and what problems are you running into?
hb52134214 wrote: complicates the application design if more than one UI element needs to refer to the model item
Again, not sure I follow. Can you give an example of how multiple UI elements referring to the same model item complicates things? I'm envisioning a TextBlock and a TextBox binding to the same item... I don't see a problem with that.
hb52134214 wrote: I really want the UI cleanly separated from the model
Some people suggest MVVM. However, I never really have liked the concept of a view model. For more complex models (custom trees and such), rebuilding that as a view model seems like a lot of work. Sometimes, though, it is really easy to create a model and a view model. I personally don't stick to any particular design pattern religiously... I just try them and use them when I feel it's appropriate.
|
|
|
|
|
With regard to routed commands:
Lets say my application has two (bubbling) routed commands: SaveFile and SaveProject. The application also has a tree structure that represents a nested heirarchy of files and projects (and maybe other stuff as well). Lets say I have the following trivial heirarchical data templates (HDT):
<HDT x:Key="pItem" DT="{x:Type c:Project}" IS="{Binding Children}">
<TextBlock Text="{Binding Name}" />
</HDT>
<HTD x:Key="fItem" DT="{x:Type c:File}" IS="{Binding Children}">
<TextBlock Text="{Binding Name}" />
</HDT>
<HTD x:Key="other" DT="{x:Type c:Project}" IS="{Binding Children}">
<TextBlock Text="{Binding Name}" />
</HDT>
How does one attach a routed command handler in the template to get a node to respond to a SaveFile command. In anything else, I'd throw in the basic:
<CommandBindings>
<CommandBinding Command="{x:Static c:Cmds.SaveFile}" CanExecute="CanSave" Execute="Save"/>
</CommandBindings>
Unfortunately, I haven't been able to achieve this simple solution with a Heirarchical data template. Any suggestions?
On a side note, the ItemsControl (and thus TreeView & TreeViewItem) has a virtual function GetContainerForItemOverride, which allows one to return the container for their control, but unfortunately this call doesn't pass the object (or even the type) of object for which the container is being constructed. If it had, then it would be so trivial to implement a treeview that generates custom tree nodes without loosing any of the nice templating, styling or anything else. Too bad.
With regard to multiple UI elements refering to the same model item:
The link referenced in my original post showed how simple it is to use the model and have information update between the UI and the model. In the example, the author was searching for text in a tree. Because he linked the 'IsSelected' property of the TreeViewItem to a property (say 'ItemIsSelected' for clarity) in the model, he could walk the tree, and successively select each matching node in the search by merely setting the 'ItemIsSelected' property. Nice. I agree.
Now, throw that model into two separate trees and oops, setting the 'ItemIsSelected' causes both trees to change their selected item. Inorder to prevent that, but have that sort of functionality in both trees, one has to implement two properties in the model: 'ItemIsSelected_TV1', and 'ItemIsSelected_TV2' and in the different TreeView's.
The alternative is to use GetContainerFromElement. This technique more cleanly separates the UI and model, though I have to agree with the example's elegance (minus the resulting attachment to the UI).
|
|
|
|
|
On some further reflection, I could add the command bindings dynamically in the TreeView and TreeViewItem function 'PrepareContainerForItemOverride(DependencyObject obj, object item).' I'd prefer to put it in the template though, so if you do know how to do that, that would be much nicer.
|
|
|
|
|
hb52134214 wrote: How does one attach a routed command handler in the template to get a node to respond to a SaveFile command.
You could have a button inside the HDT. Set its Command to SaveFile and the CommandParameter to the current DataContext. The CommandParameter set to the current DataContext tells code later on which File was clicked. Then, add the CommandBinding to the TreeView's CommandBindings (or CommandBindings higher up).
hb52134214 wrote: one has to implement two properties in the model: 'ItemIsSelected_TV1', and 'ItemIsSelected_TV2' and in the different TreeView's
You could always make ItemIsSelected an array or list of booleans. Then, in your binding, you can reference it in the trees like this:
{Binding ItemIsSelected[0]}
{Binding ItemIsSelected[1]}
That way, you can use any number of trees without having to modify the view model. And if you don't want to fill in ItemIsSelected with a certain number of items in advance (say, 2 items), you could always create a custom collection (probably derived from IList) that fills in values if they do not already exist and returns a default the first time they are accessed. So, the following binding would cause 3 items to be in the collection:
{Binding ItemIsSelected[2]}
|
|
|
|
|
The issue with the button is that the button essentially becomes the only way to trigger the Save command. You can't just catch the CanExecute and Execute events of the command. Consider a simple tree:
TV (tree view)
obj 1
obj 2
Say obj 1 is a project and obj 2 is a file. Obj 2 is selected, and the user hits the SaveProject or SaveFile menu item, or tool bar button, or key gesture. The event bubbles up the stack, but the stack really looks like:
TV
TVI_1
TVI_1_header (obj1)
TVI_1_items
TVI_2
TVI_2_header (obj2)
TVI_2_items
Before, when I said Obj 2 is selected, now it is interesting to consider... is TVI_2_header selected, or is TVI_2 selected? It could be the routed event would follow the path:
TVI_2_header -> TVI_2 -> TVI_1_items -> TVI_1 -> TV -> ...
Or,
TVI_2 -> TVI_1_items -> TVI_1 -> TV -> ...
Now consider the two events: SaveProject, and SaveFile. SaveProject never triggers (its not on the element chain). SaveFile only triggers when TVI_2_header is selected.
If anyone has any ideas for this, I'd love to hear them.
|
|
|
|
|
I think I'll write an article on this, because this TreeView issue really bugs me. I seem to always run it and it drives me nuts. Prior to now, I've just handled event in the TreeView, but its so much nicer for things to connect directly. Alas, I have a technique that works quite nicely.
To solve this problem, create an interface that enumerates command bindings. Say:
interface ICmdHandler {
IEnumerable<CommandBinding> CommandBindings { get; }
}
Next derive a class from TreeViewItem that determines if the header object is a command handler and then link the commands if it is.
class TVICommandForwarder : TreeViewItem {
protected override void OnHeaderChanged(object oldHeader, object newHeader) {
base.OnHeaderChanged(oldHeader, newHeader);
ICmdHandler oldCH = oldHeader as ICmdHandler;
ICmdHandler newCH = newHeader as ICmdHandler;
if (oldCH != null)
foreach (CommandBinding cb in oldCH.CommandBindings)
CommandBindings.Remove(cb);
if (newCH != null)
foreach (CommandBinding cb in newCH.CommandBindings)
CommandBindings.Add(cb);
}
protected override DependencyObject GetContainerForItemOverride() {
return new TVICommandForwarder();
}
}
Notice that if the header changes, it unlinks commands from the old one and links commands from the new header. Also notice that GetContainerForItemOverride() generates a new TVICommandForwarder class, which makes sure that any child nodes also support this mechanism.
Next, one needs to derive a class from TreeView so that it builds nodes using the TVICommandForwarder class.
class TVCommandForwarder : TreeView {
protected override DependencyObject GetContainerForItemOverride() {
return new TVICommandForwarder();
}
}
With that, now any object that gets loaded into the tree automatically gets its command handlers linked if the ICmdHandler interface is implemented. Now that is nice.
If anyone sees a fundamental error in my approach, please let me know. Otherwise, in the next few days I'll write up an article about this technique.
|
|
|
|
|
Dear Friends,
How to Do ZoomIn and Zoomout in Silverlight.Using Slider,
or Anyother Way Possible Suggest.
Thanks and Regards,
Munna
Muneer
|
|
|
|
|
|
Check this, http://forums.silverlight.net/forums/t/5941.aspx
April
Comm100 - Leading Live Chat Software Provider
modified 27-May-14 21:44pm.
|
|
|
|
|
Hello,
While creating a WPF application, I am facing issue with the WPF window style. As per requirement, I have to design the customize Control box (other than the default blue and the close/ min/ max/ restore button) but not able to do that.
Another way is by hide/ remove the ‘control box’ from the WPF window and add the head section on it. I can able to do that using the WPF window property WindowStyle = none.
But that hides the windows XP Taskbar too. Please suggest me that how can I implement that.
Regards
Manish Mukatimodified on Wednesday, February 17, 2010 12:50 AM
|
|
|
|
|
OKAY -- I've done a ton of searching and I've not found anything that can directly help me with what I need to do.
I'm building a business application with Silverlight 3.0 and I'm down to my VERY LAST issue!
I have 3 ComboBox controls (building, datacenter, locationType) where datacenter has a dependancy on building.
I have a listbox with customers (works great).
When a customer is selected, a list of existing locations is populated. (works great)
For these (and other) populated controls, I put out a message "loading...blah blah blah" then when the data comes back I display "data loaded...blah blah blah" which works great.
I've got my datacenter dependancy working great as well. Pick a building and the correct set of datacenters is loaded.
My editor fields are wrapped in a grid and a datasource for my location object was created. I populate it in my code by setting editorContainer.DataContext = selectedCustomerLocation; editorContainer is the grid that wraps all of my editor controls. Each control that edits the fields of the control is bound to the datacontext of the grid, but Expression does not seem to place the parent object name as a fully-qualified name. (example my xaml says 'BuildingNumber' instead of CustomerLocation.BuildingNumber) I expected the editor controls to self populate with the data once DataContext was set. (doesn't work)
I also want each combobox to display the correct selected item. I know I need to say SelectedText = "{Binding {fieldName} Converter=myValueConverter, ConverterParameter= ....". I also expected that in the Convert logic I perform the linq to lookup the building enumerated object and return the text value for the integer returned in the customer location object.
Not quite sure how to explicitely pass to the converter the value of the building ID (for example) AND the list of building name/values to have it return the correct text. So this is the first question which is the syntax to pass parameters into the converter?
The second question, then, is Expression put the datacontext in a self-contained location within the grid followed by my fields. Do I have to extend the <datacontext> end tag to wrap my editor controls? Or is DataContext all wrong? I think I saw one guy use Data Template???
Any help at all would be great. I found a ton of examples but all of them are either too simplistic (working with internal collections statically created and never dealing with an externally selected object to bind with) or buried within the context of a DataGrid which I'm not using.
modified on Monday, January 4, 2010 4:53 PM
|
|
|
|
|
Michael Eber wrote: SelectedText = "{Binding {fieldName} Converter=myValueConverter, ConverterParameter=
A trick I used to pass multple values (my entire collection) to the converter was to not bind to the field name. Try this - SelectedText = "{Binding Converter=myValueConverter, ConverterParameter= ....".
Michael Eber wrote: The second question, then, is Expression put the datacontext in a self-contained location within the grid followed by my fields. Do I have to extend the end tag to wrap my editor controls? Or is DataContext all wrong? I think I saw one guy use Data Template???
Not quite sure I understand your question. However, IMO, the datacontext looks fine. DataTemplates are used to specify the visual structure of a data object, so DataContexts and DataTemplates are actually two different things (used differently).
There are only 10 types of people in this world — those who understand binary, and those who don't. |
|
|
|
|
|
What I mean as far as passing data to the converter is this:
I need to pass the collection of objects that populate the dropdown box.
I also need to pass the value set by the object.
I've seen a setup like this for passing a date: ConvertParameter=0\d\ But I have no idea what that means or how they are actually passing the date field.
|
|
|
|
|
Michael Eber wrote: ConvertParameter=0\d
AFAIK, ConvertParameter does not support binding. So, you can only pass 'hardcoded' values like 0\d, which will format your date. The date is passed using the binding value e.g. Text="{Binding myDate, Converter={StaticResource myConverter}}" .
However, the entire collection can be passed into the converter. The appropriate value(s) can then be used inside the converter to construct the value you want to display in your UI.
There are only 10 types of people in this world — those who understand binary, and those who don't. |
|
|
|
|
|
Hello,
I'm studying for the WPF exam and playing with the different setting in the GridSplitter control and one of the behaviours makes no sense to me.
Here is the XAML:
<Grid Name="grid1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="5"/>
<ColumnDefinition Width="173"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<ListBox Name="listbox1" Grid.Column="0" SelectionChanged="listbox1_SelectionChanged"></ListBox>
<GridSplitter Name="gridsplitter1" Margin="0" Width="5" Grid.Column="1" Grid.RowSpan="2" ResizeBehavior="PreviousAndNext" HorizontalAlignment="Left" VerticalAlignment="Stretch"/>
<RichTextBox Grid.Column="2" Name="richtextbox1" />
<TextBox Grid.Column="0" Grid.Row="1"/>
<TextBox Grid.Column="2" Grid.Row="1"/>
</Grid>
When I use the splitter it resizes the previous column (0) but not the next (2), it just trundles across the window not changing size.
I know I can get the desired behaviour by just changing the third column to a proportional size but then it's the proportioning that is changing the column size not the splitter (and I'd get the same result if I put it back the ResizeBehavior to the default "BasedOnAlignment").
What am I missing here? Or is there no point to the PreviousAndNext setting?
Thanks,
Robert.
Robert
|
|
|
|
|
You have an absolute size for the last column. This size will be retained when you attempt the resize, hence the "move". Change it as follows:
<Grid Name="grid1" Width="278">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="5"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<ListBox Name="listbox1" Grid.Column="0">
</ListBox>
<GridSplitter
Name="gridsplitter1"
Width="5"
Grid.Column="1"
Grid.RowSpan="2"
HorizontalAlignment="Left"
Margin="0"
VerticalAlignment="Stretch"
ResizeBehavior="PreviousAndNext"/>
<RichTextBox Name="richtextbox1" Grid.Column="2"/>
<TextBox Grid.Column="0" Grid.Row="1"/>
<TextBox Grid.Column="2" Grid.Row="1"/>
</Grid>
In order to see the effect, I limited your grid width to 278.
"WPF has many lovers. It's a veritable porn star!" - Josh Smith As Braveheart once said, "You can take our freedom but you'll never take our Hobnobs!" - Martin Hughes.
My blog | My articles | MoXAML PowerToys | Onyx
|
|
|
|
|
Yes, I know about the using the * for the last column but I have two points of confusion with this.
1) The first column has an absolute size but it has no issue resizing that.
2) If we are going to set the 3rd column width to * we might as well go with the default ResizeBehavior of BasedOnAlignment as we will get exactly the same behaviour - hence why I wonder if PreviousAndNext has any purpose.
(I've explicitly set the ResizeBehavior but could have omitted it as BasedOnAlignment is the default):
<Grid Name="grid1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="5"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<ListBox Name="listbox1" Grid.Column="0" SelectionChanged="listbox1_SelectionChanged"></ListBox>
<GridSplitter Name="gridsplitter1" Margin="0" Width="5" Grid.Column="1" Grid.RowSpan="2" ResizeBehavior="BasedOnAlignment" HorizontalAlignment="Left" VerticalAlignment="Stretch"/>
<RichTextBox Grid.Column="2" Name="richtextbox1" />
<TextBox Grid.Column="0" Grid.Row="1"/>
<TextBox Grid.Column="2" Grid.Row="1"/>
</Grid>
Actually even if we use "BasedOnAlignment" but change the 3rd column back to an absolute width and set the HorizontalAlignment to "Right" it still won't resize the 3rd column, it just moves it across again. I can't see why there should be a difference in the behaviour (beyond which column is targeted) between setting the alignment to left or right.
|
|
|
|
|
Have a look at what happens if you add a second splitter. It's a bit of fun:
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid Name="grid1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" MinWidth="100"/>
<ColumnDefinition Width="5"/>
<ColumnDefinition Width="173"/>
<ColumnDefinition Width="5"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<ListBox Name="listbox1" Grid.Column="0">
</ListBox>
<GridSplitter
Width="5"
Grid.Column="1"
Grid.RowSpan="2"
HorizontalAlignment="Right"
Margin="0"
VerticalAlignment="Stretch"
ResizeBehavior="PreviousAndNext"/>
<GridSplitter
Width="5"
Grid.Column="3"
Grid.RowSpan="2"
HorizontalAlignment="Right"
Margin="0"
VerticalAlignment="Stretch"
ResizeBehavior="PreviousAndNext"/>
<RichTextBox Grid.Column="2"/>
<RichTextBox Grid.Column="0" Grid.Row="1"/>
<TextBox Grid.Column="2" Grid.Row="1"/>
<RichTextBox Grid.Column="4"/>
<TextBox Grid.Column="4" Grid.Row="1"/>
</Grid>
</Page>
"WPF has many lovers. It's a veritable porn star!" - Josh Smith As Braveheart once said, "You can take our freedom but you'll never take our Hobnobs!" - Martin Hughes.
My blog | My articles | MoXAML PowerToys | Onyx
|
|
|
|
|
Hi All,
I need to create a editable Workflow in run time.
Is is possible?
Please help me with this.
Thanks in advance.
Ramkumar
("When you build bridges you can keep crossing them. ")
http://ramkumarishere.blogspot.com
|
|
|
|
|
Hmm Interesting... Well I would use reflections. Does it need to be a graphical work flow? If so there is a nice WPF Work flow front end here on CP that would work for the graphical front end. I am using it in a 'Visual Power Shell' article...
Here is the link to the work flow designer...
WPF Diagram Designer - Part 2[^]
|
|
|
|
|
for example i want to animate the width of grid from 0 to its Auto Value! i've searched alot but cannot find anything, thanks in advance!
|
|
|
|
|
You will have to apply a resize animation.
Check this out[^].
There are only 10 types of people in this world — those who understand binary, and those who don't. |
|
|
|
|
|
Hi everybody.
I'm gonna create a ListView in WPF like below image via XAML and C#
http://xs.to/image-A835_4B3EF7EE.jpg[^]
I've already read some articles like this one[^] , but I'm a little confusing.
Could you please guide me , how I can do it ?
Thanks.
|
|
|
|
|