How are DynamicResources built and their use in contextmenus - c#

Are dynamic resources truly dynamic? If I define a DynamicResource, I realise that an expression is created (where?) that is not translated into a resource until runtime, however, What I do not understans is whether this dynamicresouce, once built, is now "Static"
For instance, if I create a context menu via a dynamicresource, are the menuitems which are created at runtime on access then static, even if they are bound?
If so, how can i create a dynamic context menu in XAML?

This is a very complex subject because there are so many kinds of dynamism within WPF. I will start with a simple example to help you understand some basic concepts you need, then proceed to explain the various ways in which a ContextMenu can be dynamically updated and/or replaced, and how DynamicResource fits into the picture.
Initial example: Dynamically updating ContextMenu referenced through StaticResource
Let's say you have the following:
<Window>
<Window.Resources>
<ContextMenu x:Key="Vegetables">
<MenuItem Header="Broccoli" />
<MenuItem Header="Cucumber" />
<MenuItem Header="Cauliflower" />
</ContextMenu>
</Window.Resources>
<Grid>
<Ellipse ContextMenu="{StaticResource Vegetables}" />
<TextBox ContextMenu="{StaticResource Vegetables}" ... />
...
</Grid>
</Window>
** Note the use of StaticResource for now.
This XAML will:
Construct a ContextMenu object with three MenuItems and add it to Window.Resources
Construct an Ellipse object with a reference to the ContextMenu
Construct a TextBox object with a reference to the ContextMenu
Since both the Ellipse and the TextBox have references to the same ContextMenu, updating the ContextMenu will change the options available on each. For example the following will add "Carrots" to the menu when a button is clicked.
public void Button_Click(object sender, EventArgs e)
{
var menu = (ContextMenu)Resources["Vegetables"];
menu.Items.Add(new MenuItem { Header = "Carrots" });
}
In this sense every ContextMenu is dynamic: Its items can be modified at any time and the changes will immediately take effect. This is true even when the ContextMenu is actually open (dropped down) on the screen.
Dynamic ContextMenu updated through data binding
Another way in which a single ContextMenu object is dynamic is that it responds to data binding. Instead of setting individual MenuItems you can bind to a collection, for example:
<Window.Resources>
<ContextMenu x:Key="Vegetables" ItemsSource="{Binding VegetableList}" />
</Window.Resources>
This assumes VegetableList is declared as an ObservableCollection or some other type that implements the INotifyCollectionChanged interface. Any changes you make to the collection will instantly update the ContextMenu, even if it is open. For example:
public void Button_Click(object sender, EventArgs e)
{
VegetableList.Add("Carrots");
}
Note that this kind of collection update need not be made in code: You can also bind the vegetable list to a ListView, DataGrid, etc so that changes may be made by the end-user. These changes will also show up in your ContextMenu.
Switching ContextMenus using code
You can also replace the ContextMenu of an item with a completely different ContextMenu. For example:
<Window>
<Window.Resources>
<ContextMenu x:Key="Vegetables">
<MenuItem Header="Broccoli" />
<MenuItem Header="Cucumber" />
</ContextMenu>
<ContextMenu x:Key="Fruits">
<MenuItem Header="Apple" />
<MenuItem Header="Banana" />
</ContextMenu>
</Window.Resources>
<Grid>
<Ellipse x:Name="Oval" ContextMenu="{StaticResource Vegetables}" />
...
</Grid>
</Window>
The menu can be replaced in code like this:
public void Button_Click(object sender, EventArgs e)
{
Oval.ContextMenu = (ContextMenu)Resources.Find("Fruits");
}
Note that instead of modifying the existing ContextMenu we are switching to a completely different ContextMenu. In this situation both ContextMenus are built immediately when the window is first constructed, but the Fruits menu is not used until it is switched.
If you want to avoid constructing the Fruits menu until it was necessary you could construct it in the Button_Click handler instead of doing it in XAML:
public void Button_Click(object sender, EventArgs e)
{
Oval.ContextMenu =
new ContextMenu { ItemsSource = new[] { "Apples", "Bananas" } };
}
In this example, every time you click on the button a new ContextMenu will be constructed and assigned to the oval. Any ContextMenu defined in Window.Resources still exists but is unused (unless another control uses it).
Switching ContextMenus using DynamicResource
Using DynamicResource allows you to switch between ContextMenus without explicitly assigning it code. For example:
<Window>
<Window.Resources>
<ContextMenu x:Key="Vegetables">
<MenuItem Header="Broccoli" />
<MenuItem Header="Cucumber" />
</ContextMenu>
</Window.Resources>
<Grid>
<Ellipse ContextMenu="{DynamicResource Vegetables}" />
...
</Grid>
</Window>
Because this XAML uses DynamicResource instead of StaticResource, modifying the dictionary will update the ContextMenu property of the Ellipse. For example:
public void Button_Click(object sender, EventArgs e)
{
Resources["Vegetables"] =
new ContextMenu { ItemsSource = new[] {"Zucchini", "Tomatoes"} };
}
The key concept here is that DynamicResource vs StaticResource only controls when the dictionary is lookup is done. If StaticResource is used in the above example, assigning to Resources["Vegetables"] will not update the Ellipse's ContextMenu property.
On the other hand, if you are updating the ContextMenu itself (by changing its Items collection or via data binding), it does not matter whether you use DynamicResource or StaticResource: In each case any changes you make to the ContextMenu will be immediately visible.
Updating individual ContextMenu ITEMS using data binding
The very best way to update a ContextMenu based on properties of the item that is right-clicked is to use data binding:
<ContextMenu x:Key="SelfUpdatingMenu">
<MenuItem Header="Delete" IsEnabled="{Binding IsDeletable}" />
...
</ContextMenu>
This will cause the "Delete" menu item to be automatically grayed out unless the item has its IsDeletable flag set. No code is necessary (or even desirable) in this case.
If you want to hide the item instead of simply graying it out, set Visibility instead of IsEnabled:
<MenuItem Header="Delete"
Visibility="{Binding IsDeletable, Converter={x:Static BooleanToVisibilityConverter}}" />
If you want to add/remove items from a ContextMenu based on your data, you can bind using a CompositeCollection. The syntax is a bit more complex, but it is still quite straightforward:
<ContextMenu x:Key="MenuWithEmbeddedList">
<ContextMenu.ItemsSource>
<CompositeCollection>
<MenuItem Header="This item is always present" />
<MenuItem Header="So is this one" />
<Separator /> <!-- draw a bar -->
<CollectionContainer Collection="{Binding MyChoicesList}" />
<Separator />
<MenuItem Header="Fixed item at bottom of menu" />
</CompositeCollection>
</ContextMenu.ItemsSource>
</ContextMenu>
Assuming "MyChoicesList" is an ObservableCollection (or any other class that implements INotifyCollectionChanged), items added/removed/updated in this collection will be immediately visible on the ContextMenu.
Updating individual ContextMenu ITEMS without data binding
When at all possible you should control your ContextMenu items using data binding. They work very well, are nearly foolproof, and greatly simplify your code. Only if data binding can't be made to work does it make sense to use code to update your menu items. In this case you can build your ContextMenu by handling the ContextMenu.Opened event and doing updates within this event. For example:
<ContextMenu x:Key="Vegetables" Opened="Vegetables_Opened">
<MenuItem Header="Broccoli" />
<MenuItem Header="Green Peppers" />
</ContextMenu>
With this code:
public void Vegetables_Opened(object sender, RoutedEventArgs e)
{
var menu = (ContextMenu)sender;
var data = (MyDataClass)menu.DataContext
var oldCarrots = (
from item in menu.Items
where (string)item.Header=="Carrots"
select item
).FirstOrDefault();
if(oldCarrots!=null)
menu.Items.Remove(oldCarrots);
if(ComplexCalculationOnDataItem(data) && UnrelatedCondition())
menu.Items.Add(new MenuItem { Header = "Carrots" });
}
Alternatively this code could simply change menu.ItemsSource if you were using data binding.
Switching ContextMenus using Triggers
Another technique commonly used to update ContextMenus is to use a Trigger or DataTrigger to switch between a default context menu and a custom context menu depending on the triggering condition. This can handle situations where you want to use data binding but need to replace the menu as a whole rather than update parts of it.
Here is an illustration of what this looks like:
<ControlTemplate ...>
<ControlTemplate.Resources>
<ContextMenu x:Key="NormalMenu">
...
</ContextMenu>
<ContextMenu x:Key="AlternateMenu">
...
</ContextMenu>
</ControlTemplate.Resources>
...
<ListBox x:Name="MyList" ContextMenu="{StaticResource NormalMenu}">
...
<ControlTemplate.Triggers>
<Trigger Property="IsSpecialSomethingOrOther" Value="True">
<Setter TargetName="MyList" Property="ContextMenu" Value="{StaticResource AlternateMenu}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
In this scenario it is still possible to use data binding to control individual items in both NormalMenu and AlternateMenu.
Releasing ContextMenu resources when the menu is closed
If resources used in a ContextMenu are expensive to keep in RAM you may want to release them. If you are using data binding this is likely to happen automatically, as the DataContext is removed when the menu is closed. If you are using code instead you may have to catch the Closed event on the ContextMenu to deallocate whatever you created in response to the Opened event.
Delayed construction of ContextMenu from XAML
If you have a very complex ContextMenu that you want to code in XAML but don't want to load except when it is needed, two basic techniques are available:
Put it in a separate ResourceDictionary. When necessary, load that ResourceDictionary and add it to MergedDictionaries. As long as you used DynamicResource, the merged value will be picked up.
Put it in a ControlTemplate or DataTemplate. The menu will not actually be instantiated until the template is first used.
However neither of these techniques by itself will cause the loading to happen when the context menu is opened - only when the containing template is instantiated or the dictionary is merged. To accomplish that you must use a ContextMenu with an empty ItemsSource then assign the ItemsSource in the Opened event. However the value of the ItemsSource can be loaded from a ResourceDictionary in a separate file:
<ResourceDictionary ...>
<x:Array x:Key="ComplexContextMenuContents">
<MenuItem Header="Broccoli" />
<MenuItem Header="Green Beans" />
... complex content here ...
</x:Array>
</ResourceDictionary>
with this code in the Opened event:
var dict = (ResourceDictionary)Application.LoadComponent(...);
menu.ItemsSource = dict["ComplexMenuContents"];
and this code in the Closed event:
menu.ItemsSource = null;
Actually if you have only a single x:Array, you may as well skip the ResourceDictionary. If your XAML's outermost element is the x:Array the Opened event code is simply:
menu.ItemsSource = Application.LoadComponent(....)
Summary of critical concepts
DynamicResource is used only for switching values based on which resource dictionaries are loaded and what they contain: When updating the contents of the dictionaries, DynamicResource automatically updates the properties. StaticResource only reads them when the XAML is loaded.
No matter whether DynamicResource or StaticResource is used, the ContextMenu is created when the resource dictionary is loaded not when the menu is opened.
ContextMenus are very dynamic in that you can manipulate them using data binding or code and the changes immediately take effect.
In most cases you should update your ContextMenu using data bindings, not in code.
Completely replacing menus can be done with code, triggers, or DynamicResource.
If contents must be loaded into RAM only when the menu is open, they can be loaded from a separate file in the Opened event and cleared out in the Closed event.

Related

Editing a local resource's visibility in codebehind

I am fairly new to WPF and have struggled trying to find an answer to this so maybe I am going about it the wrong way.
I have a ContextMenu that I wish to use multiple places so I have it defined as a Resource:
<Window.Resources>
<ContextMenu x:Key="MainContextMenu">
<MenuItem Header="Select All" Click="SelectAllButton_Click"/>
<MenuItem Header="Clear All" Click="ClearAllButton_Click"/>
<MenuItem Header="Export" Click="ExportButton_Click" Name="ExportCM"/>
<MenuItem Header="Priority" Click="PriorityButton_Click" Name="PriorityCM"/>
<MenuItem Header="Cancel" Click="CancelButton_Click" Name="CancelCM"/>
<MenuItem Header="Reallocate" Click="ReallocateButton_Click" Name="ReallocateCM"/>
<MenuItem Header="Release" Click="ReleaseButton_Click" Name="ReleaseCM"/>
<MenuItem Header="Hazard" Click="HazardButton_Click" Name="HazardCM"/>
<MenuItem Header="Reset" Click="ResetButton_Click" Name="ResetCM"/>
</ContextMenu>
</Window.Resources>
I also have a Menu with items with identical headers and click handlers but the Menu is not a resource since I only needed to place it once. With the Menu I am able to edit the visibility of certain MenuItems in codebehind. I would like to be able to do the same to my ContextMenu.
How can I access an individual ContextMenu MenuItem and set its visibility in code behind if my ContextMenu is a locally defined static resource?
You're looking for Custom Controls in WPF. You can extend a WPF control where you can add all your Menus / Menus Items and handle them as objects using XAML.
http://wpftutorial.net/HowToCreateACustomControl.html
After doing that, inside the Window you want to use your custom Menu, you need to add the namespace like in:
xmlns:controls="clr-namespace:YourProject.YourControl"
And then you can use your menu like this:
<controls:YourControl>
Also take a look at DataTemplates.
ContextMenu ctxmenu = (ContextMenu)this.Resources["MainContextMenu"];
And if you assign this context menu to say Button:Btn1, then Btn1.ContextMenu will give you the context menu of button Btn1.
To access a particular menuitem, you have btn1.ContextMenu.Items collections to play with.

WPF: Which solution? TabControl with close button and new tab button

I'm trying to find the best solution for a TabControl that both support a close button on each TabItem, and always show a "new tab button" as the last tab.
I've found some half working solutions, but i think that was for MVVM, that I'm not using. Enough to try to understand WPF =)
This is the best solution I've found so far:
http://www.codeproject.com/Articles/493538/Add-Remove-Tabs-Dynamically-in-WPF
A solution that i actually understand. But the problem is that it is using the ItemsSource, and i don't want that. I want to bind the ItemsSource to my own collection without having to have special things in that collection to handle the new tab button.
I've been search for days now but cant find a good solution.
And I'm really new to WPF, otherwise i could probably have adapted the half done solutions I've found, or make them complete. But unfortunately that is way out of my league for now.
Any help appreciated.
I have an open source library which supports MVVM and allows extra content, such as a button to be added into the tab strip. It is sports Chrome style tabs which can tear off.
http://dragablz.net
This is bit of a dirty way to achieve the Add (+) button placed next to the last TabItem without much work. You already know how to place a Delete button next to the TabItem caption so I've not included that logic here.
Basically the logic in this solution is
To bind ItemsSource property to your own collection as well as
the Add TabItem using a CompositeCollection.
Disable selection of
the Add(+) TabItem and instead perform an action to load a new tab when it
is clicked/selected.
XAML bit
<TextBlock x:Name="HiddenItemWithDataContext" Visibility="Collapsed" />
<TabControl x:Name="Tab1" SelectionChanged="Tab1_SelectionChanged" >
<TabControl.ItemsSource>
<CompositeCollection>
<CollectionContainer Collection="{Binding DataContext.MyList, Source={x:Reference HiddenItemWithDataContext}}" />
<TabItem Height="0" Width="0" />
<TabItem Header="+" x:Name="AddTabButton"/>
</CompositeCollection>
</TabControl.ItemsSource>
</TabControl>
The code behind
private void Tab1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.AddedItems.Contains(AddTabButton))
{
//Logic for adding a new item to the bound collection goes here.
string newItem = "Item " + (MyList.Count + 1);
MyList.Add(newItem);
e.Handled = true;
Dispatcher.BeginInvoke(new Action(() => Tab1.SelectedItem = newItem));
}
}
You could make a converter which appends the Add tab. This way the collection of tabs in you viewmodel will only contain the real tabs.
The problem is then how to know when the Add tab is selected. You could make a TabItem behavior which executes a command when the tab is selected. Incidentally I recommended this for another question just recently, so you can take the code from there: TabItem selected behavior
While I don't actually have the coded solution, I can give some insight on what is most likely the appropriate way to handle this in a WPF/MVVM pattern.
Firstly, if we break down the request it is as follows:
You have a sequence of elements that you want to display.
You want the user to be able to remove an individual element from the sequence.
You want the user to be able to add a new element to the sequence.
Additionally, since you are attempting to use a TabControl, you are also looking to get the behavior that a Selector control provides (element selection), as well as an area to display the element (content) which is selected.
So, if we stick to these behaviors you'll be fine, since the user interface controls can be customized in terms of look and feel.
Of course, the best control for this is the TabControl, which are you already trying to use. If we use this control, it satisfies the first item.
<TabControl ItemsSource="{Binding Path=Customers}" />
Afterwards, you can customize each element, in your case you want to add a Button to each element which will execute a command to remove that element from the sequence. This will satisfy the second item.
<TabControl ...>
<TabControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=CustomerId}" />
<Button Command="{Binding Path=RemoveItemCommand, Mode=OneTime,
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type TabControl}}"
CommandParameter="{Binding}" />
</StackPanel>
</DataTemplate>
<TabControl.ItemTemplate>
</TabControl>
The last part is a bit more difficult, and will require you to actually have to create a custom control that inherits from the TabControl class, add an ICommand DependencyProperty, and customize the control template so that it not only displays the TabPanel, but right next to it also displays a Button which handles the DependencyProperty you just created (the look and feel of the button will have to be customized as well). Doing all of this will allow you to display your own version of a TabControl which has a faux TabItem, which of course is your "Add" button. This is far far far easier said than done, and I wish you luck. Just remember that the TabPanel wraps onto multiple rows and can go both horizontally or vertically. Basically, this last part is not easy at all.

WPF - Focus Control Within DataTemplate applied to FlyoutControl

I have a DataTemplate which contains a TextBox. The DataTemplate is bound to the ContentTemplate property of a Style for the DevExpress FlyoutControl. The Flyout Control itself is within the ControlTemplate of another TextBox.
When the TextBox with the FlyoutControl is focused, I want to redirect focus to the first TextBox in the FlyoutControl's ContentTemplate (from the DataTemplate). Setting FocusManager.FocusedElement={Binding RelativeSource={RelativeSource Self}} on the TextBox I want focused accomplishes this the first time, but once the Flyout has loaded it no longer works.
I have tried every suggestion I can find and nothing so far has worked. I can get the TextBox I want to reference in code and call Focus(), but it always returns false. At best, when I try to focus it in code, the Flyout is focused instead, but never the TextBox within the Flyout.
Here is what each relevant part looks like (irrelevant code omitted):
<DataTemplate x:Key="FlyoutTemplate">
<Grid>
<dxe:TextEdit x:Name="TextThatWantsFocus"
FocusManager.FocusedElement={Binding RelativeSource={RelativeSource Self}}" />
</Grid>
</DataTemplate>
...
<Style x:Key="FlyoutStyle" TargetType="dxe:FlyoutControl">
<Setter Property="ContentTemplate" Value="{StaticResource FlyoutTemplate}"/>
</Style>
...
<dxe:TextEdit>
<dxe:TextEdit.Template>
<ControlTemplate>
<StackPanel>
<dxe:TextEdit x:Name="InnerTextEdit" />
<dxe:FlyoutControl Style="{StaticResource FlyoutStyle}"/>
</StackPanel>
</ControlTemplate>
</dxe:TextEdit.Template>
</dxe:TextEdit>
The flyout is being opened in code. It is here that I also would like to focus the TextBox (TextThatWantsFocus). However, nothing I have tried will give it focus (except for FocusManager handling it the first time), including the typical SO answer involving triggers. Any ideas would be greatly appreciated.
I took DmitryG's advice and submitted a DevExpress support ticket, and they were able to provide a solution.
The issue was resolved by handling the Loaded event of the TextEdit I want focused and using the dispatcher to focus it:
private void TextThatWantsFocus_Loaded(object obj, RoutedEventArgs e)
{
var text = obj as FrameworkElement;
Dispatcher.CurrentDispatcher.BeginInvoke(new Action(delegate()
{ text.Focus(); }));
}
I suggest you using the FocusBehavior from DevExpress MVVM Framework:
<DataTemplate x:Key="FlyoutTemplate">
<Grid>
<dxe:TextEdit>
<dxmvvm:Interaction.Behaviors>
<local:FocusBehavior/>
</dxmvvm:Interaction.Behaviors>
</dxe:TextEdit>
</Grid>
</DataTemplate>

How to bind a button on wpf grid to a method on MVVM when I am using caliburn micro

I have a Grid on a wpf window which I want to add the capability that user can delete some of the items by clicking on a delete button. The application uses Calibrun Micro to bind view to ViewModel.
My question?
1- Is it a good idea to use a button to delete an item from a grid in WPF?
2- How can I bind a button to a method on VM and in the methd get a pointer to the item that should be deleted?
Edit1
I added the buttons in this way to datagrid:
<DataGridTemplateColumn Width="100">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Content="Delete" cal:Message.Attach="DeleteFromList($dataContext)" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
and c# code follow:
public void DeleteFromList(object tmp)
{
}
But the buttons on datagrid are disabled and clicking on them doesn't fire DeleteFromList method (I checked using debugger).
Why they are disabled? How can I make them enabled?
This depends on how your button is placed - is there a single 'delete' button or have you added a button per row in the grid (are we talking DataGrid or just Grid?)
Assuming you are talking about DataGrid, you can easily just add an action message command to the button and pass through the item which is being deleted to the message handler on the VM
e.g. in the VM
public class MyViewModel
{
public DataItemCollectionTypeName ItemCollection { get; set; }
public void DeleteItem(DataItemTypeName item)
{
ItemCollection.Remove(item);
}
}
Assuming ItemCollection is bound to the grid, the button XAML may look like this:
<Button cal:Message.Attach="[Click] = [DeleteItem($datacontext)]" />
You may also need to set Action.TargetWithoutContext (it should be bound to the VM) if this is a templated row, as otherwise CM will not be able to locate the VM to invoke the action message on
If you have a single button that isn't contained within the grid you can always target the grids SelectedItem in the action message
<DataGrid x:Name="SomeDataGrid"></DataGrid>
<Button cal:Message.Attach="[Click] = [DeleteItem(SomeDataGrid.SelectedItem)]" />
It may be (and probably is) the default property that CM will look at so you may not need to specify the property name unless you have modified default conventions
<DataGrid x:Name="SomeDataGrid"></DataGrid>
<Button cal:Message.Attach="[Click] = [DeleteItem(SomeDataGrid)]" />
Edit
To clarify: In order for CM to find a VM to call the DeleteItem method it uses the DataContext of the current item. In the case of an ItemsControl derived control, the datacontext for each item points to the item being bound, not the ViewModel.
In order to give CM a hint as to which object it should try to resolve the DeleteItem method on, you can use the Action.TargetWithoutContext attached property, which applies a target object for action messages without changing the DataContext of the bound row/item
You can use element name syntax to point to the correct place:
In this example I've used a grid as the root element and named it LayoutRoot, then I've pointed the action message target to LayoutRoot.DataContext (which will be the ViewModel) using ElementName syntax. You can use any method (AncestorType or whatever)
<Grid x:Name="LayoutRoot">
<DataGridTemplateColumn Width="100">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Content="Delete" cal:Message.Attach="DeleteFromList($dataContext)" cal:Action.TargetWithoutContext="{Binding DataContext, ElementName=LayoutRoot}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</Grid>
That should then work!
You could do something like this...
<Button cal:Message.Attach="[Event MouseEnter] = [Action Save($this)]">
Check the docs as they will explain what you need to do and should answer your question: link

access-like data navigation in WPF?

What would be the best way to build a data-navigation like in access-forms in XAML/C#?
Should I build a user control (or even custom control) that I just bind to my collection in which I can put other controls? (hence this question: C# User Control that can contain other Controls (when using it) )
Or can I build something by deriving from then ItemsControl somehow? how?
Or would this be done completely different today (like "this style of navigation is so last year!")?
I'm relatively new to C# and all (not programming as such, but with more like "housewife-language" Access-VBA) also I'm no native english speaker. So pls be gentle =)
You can create user control and place a bunch of buttons (First, Prev, Next, Last, etc..) in it and place it on the main window. Secondly, you can bind your data navigation user control to a CollectionViewSource which will help you to navigate among your data.
Your main window:
<Window.Resources>
<CollectionViewSource x:Key="items" Source="{Binding}" />
</Window.Resources>
<Grid>
<WpfApplication1:DataNavigation DataContext="{Binding Source={StaticResource items}}" />
<StackPanel>
<TextBox Text="{Binding Source={StaticResource items},Path=Name}" />
</StackPanel>
</Grid>
Your Data Navigation User Control:
<StackPanel>
<Button x:Name="Prev" Click="Prev_Click"><</Button>
<Button x:Name="Next" Click="Next_Click">></Button>
<!-- and so on -->
</StackPanel>
And your click handlers goes like this:
private void Prev_Click(object sender, RoutedEventArgs e)
{
ICollectionView view = CollectionViewSource.GetDefaultView(DataContext);
if (view != null)
{
view.MoveCurrentToPrevious();
}
}
I hope this helps.
Sounds like you're after a DataGrid control. Microsoft is releasing a WPF DataGrid as part of a WPF Toolkit which you can download here: http://wpf.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=25047.

Categories

Resources