I'm using the ListBoxDragDropTarget from the Silverlight Toolkit (April 2010) with SL 4.
I want to drag items from the list box onto a Label and handle the drop event there.
However it seems a bit complicated. The regular Drop event of the Label never gets fired. I suppose that is because the Silverlight Toolkit has its own way of handling Drag & Drop which is only partially compatible.
Looking arround I found the Microsoft.Windows.DragDrop.DropEvent and attached a handler to this event. And it worked!! I got the Drop event. However I'm not sure how to get to the real object that was dragged (a string).
I tried e.Data.GetData(typeof(string)) but I got nothing. Looking at the available formats there is a System.Windows.Controls.ItemDragEventArgs object. Inside this I found an array of System.Collections.ObjectModel.Selection which then has an Item property. I suppose in this Item property I find my object, but the whole method seems a bit fragile and I'm not convinced that is the official way to do this.
Is there any better way?
U can also use another ListBox
For ex: include namespace
xmlns:toolKit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Toolkit"
Let us add the “ListBoxDragDropTarget inside the Grid. Set the attribute “AllowDrop” to True. Once it is set to true, it will be able to catch the drop event inside the control.
Now we will add a ListBox inside the ListBoxDragDropTarget and set properties whichever u like. suppose
<toolKit:ListBoxDragDropTarget AllowDrop="True">
<ListBox x:Name="customerListBoxMain" Height="200" Width="200"
DisplayMemberPath="Name">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
</toolKit:ListBoxDragDropTarget>
And add another ListBox
<toolKit:ListBoxDragDropTarget AllowDrop="True">
<ListBox Height="200" Width="200" DisplayMemberPath="Name">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
</toolKit:ListBoxDragDropTarget>
Now to fetch some data and set it to the Source of the first ListBox from code behind. Here is the sample code:
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
customerListBoxMain.ItemsSource = PersonDataProvider.GetData();
}
}
It's Done..
Related
I am working on a WPF application which is developed using MVVM pattern. The MainWindow has several Usercontrols that open when an action is performed. However, I want to close the Usercontrol once the actions are complete and on Clicking a button. I have looked in several places, but haven't had any luck with it so far. Any help would be appreciated.
It is being pointed out that my question is a duplicate of this :
Close View from ViewModel
But it is actually not, since that thread talks about closing a Window, mine is about closing an UserControl.
Adding some code to make it clear:
This is the ItemsControl in the first UserControl which hosts the second Usercontrol:
<Grid x:Name="UserControlGrid" Width="Auto" Height="auto" Margin="0,0,0,0">
<ItemsControl ItemsSource="{Binding ViewsToShow}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid IsItemsHost="True" Width="auto" Height="auto"></Grid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Grid>
Now to open the second UserControl , in the first UserControl ViewModel, I do this:
private ObservableCollection<ObservableObject> viewsToShow = new ObservableCollection<ObservableObject>();
public ObservableCollection<ObservableObject> ViewsToShow
{
get
{
return viewsToShow;
}
set
{
viewsToShow = value;
OnPropertyChanged("ViewsToShow");
}
}
ViewsToShow.Add(new SecondUserControlViewModel());
Thank you
The answer is: you should not close your usercontrols (unless they're used as separate dialogs, and this is not your case, according to your comment above).
All changes in usercontrols visibility are about navigation. Once you logically navigate to a functionality involving another usercontrol, you have to hide old one and show new control. Usually this is done via template selection:
Two templates, one per UserControl, each associated with respective ViewModel:
<DataTemplate DataType="{x:Type ViewModels:FirstViewModel}">
<controls:FirstControl />
</DataTemplate>
<DataTemplate DataType="{x:Type ViewModel:SecondViewModel}">
<controls:SecondControl />
</DataTemplate>
Then later we declare a placeholder:
<ContentControl Content="{Binding ViewModelSelector}" />
Once ViewModelSelector property returns FirstViewModel, our placeholder will show FirstControl. If we navigate ViewModelSelector property to SecondViewModel, our placeholder would auto-replace FirstControl with SecondControl and vice versa.
What I Try to Achieve:
I'm developing a Visual Studio plugin, and I need a MultiSelectComboBox. I want to fit in with the look and feel of VisualStudio so it seemed a good idea to use their own class for this:
public class MultiSelectComboBox : UserControl, IComponentConnector, IStyleConnector
Name: Microsoft.VisualStudio.Diagnostics.UI.Controls.MultiSelectComboBox
Assembly: Microsoft.VisualStudio.Diagnostics.Common, Version=12.0.0.0
Microsoft uses this class in their Code Analysis page: View/Other Windows/Code Analysis.
The Problem:
Of course it just doesn't work right when I want to use it. :)
Here's a sample code how I used it:
public TestClass()
{
InitializeComponent();
multiSelectComboBox.ItemsSource = new string[] { "Item 1", "Item 2", "Item 3" };
multiSelectComboBox.AllItemsText = "All items";
}
And here's the XAML markup:
<UserControl ...
xmlns:vsUiControls="clr-namespace:Microsoft.VisualStudio.Diagnostics.UI.Controls;assembly=Microsoft.VisualStudio.Diagnostics.Common"
...>
<vsUiControls:MultiSelectComboBox x:Name="multiSelectComboBox"/>
</UserControl>
Now the MultiSelectComboBox appear and you can interact with it, however, when you select some items, but not all, the items should be displayed like this: Item 1; Item 3 (assuming you selected all but Item 2). However, the displayed text is just Item 1Item 3, totally missing the separator.
The funny thing (that I have overlooked for quite a while) is that if you debug your code and ask for multiSelectComboBox.SelectedItemsText it returns the right values separated with the semicolon.
So the question is, if the value is stored right, why is it not displayed correctly when I use it in my code, but right when used by Microsoft on the Code Analysis page?
The XAML markup describing the style of MultiSelectComboBox contains only one instance of SelectedItemsText, which is a binding. Please see what I've got from .Net Reflector below:
<local:MultiSelectComboBox
p1:UserControl.Name="_this"
p1:AutomationProperties.Name="{Binding RelativeSource={RelativeSource Self},Path=AllItemsText}"
xmlns:p1="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:local="clr-namespace:Microsoft.VisualStudio.Diagnostics.UI.Controls;assembly=Microsoft.VisualStudio.Diagnostics.Common,Version=12.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a">
...
<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<local:CheckComboBox
CheckComboBox.Name="_comboBox"
p4:FrameworkElement.Style="{StaticResource ComboStyle}"
p4:Control.HorizontalContentAlignment="Stretch"
p4:KeyboardNavigation.DirectionalNavigation="Continue"
p4:AutomationProperties.Name="{Binding ElementName=_this,Path=SelectedItemsText,Mode=OneWay}"
xmlns:p4="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<ItemsControl.ItemTemplate>
...
</ItemsControl.ItemTemplate>
</local:CheckComboBox>
</Grid>
</local:MultiSelectComboBox>
I am not sure why SelectedItemsText is bound to the AutomationProperties.Name (attached?) property, but this is what .Net Reflector gave me. If I debug my code, I can find the semicolon separated values stored in the Name property of CheckedComboxBox control within the MultiSelectComboBox.
The values seem to be stored right, binding seems to work, yet the text displayed to the UI does not contain the separator. I'm just puzzled...
I took a look at decompiled sources and it seems that property SelectedItemsText is used only for UI automation (attached property AutomationProperties.Name). Real display text is showind with this XAML:
<TextBlock Name="PART_SummaryPartialSelection" Grid.Row="0" Style="{StaticResource DropDownTextBlockStyle}" Visibility="{Binding Path=AllItemsSelected, ElementName=_this, Converter={StaticResource booleanToVisibilityConverterNegative}}">
<ItemsControl Name="PART_Items" Focusable="False" Background="#00FFFFFF" IsHitTestVisible="False" x:Uid="M113" ItemsSource="{Binding SelectedItems, ElementName=_this}" ItemTemplate="{Binding DisplayAreaTemplate, ElementName=_this}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate x:Uid="M115">
<StackPanel IsItemsHost="True" Orientation="Horizontal" x:Uid="M116" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</TextBlock>
So it is just horizontal StackPanel with items one by one without any separator. So you will need to modify this template or just add semicolon at your items (looks like Visual Studio does it this way as it shows semicolon event after last item - item1; item2;)
Here's my issue: I have a wrapper class that contains sets of lists that contain 15 images each. I want to bind a central StackPanel to a method that actually modifies the same StackPanel that was passed to it and adds child StackPanel elements that contain 15 images each.
To clarify:
I have a central StackPanel that has a vertical orientation. This StackPanel is located inside of a DataTemplate!.
<DataTemplate>
<Grid x:Name="ImageDisplayGrid" Height="861" Width="656">
<StackPanel x:Name="CentralImagePanel" HorizontalAlignment="Left" Height="841" Margin="10,10,0,0" VerticalAlignment="Top" Width="636"/>
</Grid>
</DataTemplate>
I have many instances of my wrapper class that contain up to 15 images each (as WritableBitmap objects.
I want to bind my central StackPanel to some method that will modify that StackPanel, iterating through my list of wrapper classes and adding child StackPanel controls to the central StackPanel for each instance of my wrapper class found.
For each instance of the (ImageSet1, ImageSet2, etc for example) wrapper class, the new StackPanel that will be added to the central StackPanel will be populated using the images contained in that wrapper class instance.
In my mind there isn't really anything to be 'returned' here, so I was hoping there was a way to just pass the control (the central StackPanel) to some method, let the method modify it, and then carry on after the central StackPanel is populated with its child `StackPanels'.
To clarify even more:
Think of NetFlix. You know how you can scroll vertically through each category and each category allows you to scroll horizontally? Thats what I am trying to emulate, only I want it to be dynamic and bound to my wrapper class that contains a list of Images to use.
My main obstacle right now is that the central StackPanel is located within a DataTemplate, so there isn't an easy way to access it during runtime. On top of that it would be nicer to use a binding anyway.
I have tried to use IValueConverter to turn my wrapper class into a list of StackPanel objects that the central StackPanel can use, but that didn't work. I've also searched for ways to bind a control to a method that has no return property without any luck as well.
Any help or examples would be greatly appreciated.
You are thinking about this wrong. Really, really, wrong. StackPanel is a layout control. You shouldn't ever be directly modifying its children or any other properties.
As you've noticed, there is no real way to do this task in the way you describe.
To display collections, use an ItemsControl. In your case, it would be something like:
<ItemsControl ItemsSource="{Binding Categories}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<ItemsControl ItemsSource={"Binding Videos"}>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<!-- Whatever -->
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Notice the inner template is another ItemsControl, this time with a horizontal StackPanel as the panel template.
I'm trying to use in my application an input-selected index to scroll a ListBox (horizontally scrollable). I've found on MSDN and on this own site the method ScrollIntoView but it doesn't work and on the ListBox Class page it has been written to be compatible with WP 7.0, 7.1. So, this is a snapshot of my code...
scrolling.ScrollIntoView(scrolling.Items[20]);
where scrolling is my ListBox and the 20th item is the one I want to be selected and visualized.
PS: I've already tried to use the selectedIndex way but it is still not working!
This is a xaml of my ListBox (put in the Layout Grid) which have referencies to templates written in the App.xaml document.
<ListBox x:Name="scrolling" Grid.Column="0" ScrollViewer.ManipulationMode ="Control" ScrollViewer.VerticalScrollBarVisibility="Disabled" ScrollViewer.HorizontalScrollBarVisibility="Visible">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
edit: I found that calling the function by a button makes the all whole stuff work, but how to initialize everything at the start?
I used in my solution first updated UI and then called ScrollIntoView it works fine:
scrolling.UpdateLayout();
scrolling.ScrollIntoView(scrolling.Items[20]);
I am trying to create a kind of progress bar control in WPF. It will be ellipses that fill in as each step completes. However, I am failing at coming up what I would consider a clean example (minimal code behind and waste). Here is what I have:
<ItemsControl>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Ellipse Fill="Blue" Stretch="UniformToFill"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Then, I want to have two dependency properties:
TotalSteps
StepsCompleted
What I want is when TotalSteps = 14 then there will be 14 ellipses and the fill would work off of a trigger using StepsCompleted, a math converter and the ellipse's index. However, I haven't been able to figure out a way to do this unless I create a dummy list that is created with blank objects that will act as my DataContext...but, that seems like a waste. Is there a way to fill the template based off of the number, and not need a backing List?
Alternatively, I would accept a solution that would be an override of the progress bar template. However, I found nothing, so the user control seemed the easiest