I have a drop shadow style for a StackPanel. The content is bound to an ObservableCollection and each item is rendered as an Image. When I remove the last item from the collection, the drop shadow remains, even though the image is no longer there. This only happens with the last item.
What's going on? How do I ensure the shadow is removed too?
<Style TargetType="StackPanel" x:Key="ShadowedStackPanel">
<Setter Property="BitmapEffect">
<Setter.Value>
<DropShadowBitmapEffect Color="Black" Direction="50" ShadowDepth="5" Opacity=".65" Softness="1"/>
</Setter.Value>
</Setter>
</Style>
<ItemsControl x:Name="TilesControl">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" Style="{StaticResource ShadowedStackPanel}" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Image Source="{Binding Path=ImageSource}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
The codebehind is basically:
public ObservableCollection<TileViewModel> Hand = new ObservableCollection<TileViewModel>();
TilesControl.ItemsSource = Hand;
// populate the collection here
var last = Hand.Last();
Hand.Remove( last );
And this leaves a lingering dropshadow effect.
If I remove any other earlier item in the collection, it redraws everything fine. This only happens if I remove the last item.
If I resize the window, it gets redrawn and fixed... but for whatever reason, it leaves a lingering shadow if I don't.
How do I force the redraw so the shadow goes away? Or avoid the problem in the first place?
You could use the code after removing
TilesControl.Items.Refresh();
Related
I need to lock the Z-order of a canvas/content control after it is dragged by a Thumb.
In the below image, the "Joe Smith" pops above the others the other two ellipses while the the mouse over is active. Once the drag stops and the mouse moves out, it drops back to its value.
I am unable to find a solution within the design I have shown below to keep it locked above the others.
Minimal Reproducible Example
I have created a code gist of all code that contains the xaml, the thumb class and the people class. All one has to do is create a .Net Core WPF app and drop in the snippets of code and set name spacing in Xaml as needed.
Design
There is an ItemsControl which has DataTemplate defined with a Canvas. Each content in the ItemsControl has ContentControl which has a Thumb as applied by a style.
Another style trigger of the mouse entering the ContentPresenter has the content temporarily pushed in zIndex above the others by setting the content's internal Grid's zIndex to 1.
How to stick that zIndex?
Xaml
<ItemsControl Margin="10" ItemsSource="{Binding Source={StaticResource People}}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="1" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Canvas>
<ContentControl Width="100" Height="100" >
<Grid>
<Ellipse Fill="Silver">
<Ellipse.Effect>
<DropShadowEffect Color="Black" Direction="320" ShadowDepth="6" Opacity="0.5"/>
</Ellipse.Effect>
</Ellipse>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Margin="3,3,3,0" Text="{Binding Path=First}"/>
<TextBlock Margin="3,0,3,7" Text="{Binding Path=Last}"/>
</StackPanel>
</Grid>
</ContentControl>
</Canvas>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemContainerStyle>
<Style TargetType="{x:Type ContentPresenter}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Grid.ZIndex" Value="1"/>
</Trigger>
</Style.Triggers>
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
See the Gist for all supporting classes and styles to reproduce
Actual Design
The ultimate goal is to have a panel of images of a set size, when the user grabs the thumb the image it will move forward and lock above the others. I say this in-case there is another way to do that which could provide an answer above the minimal example design.
In my ItemsControl I changed the ItemsPanelTemplate to be a Canvas such as
<ItemsPanelTemplate>
<Canvas x:Name="MainCanvas" />
</ItemsPanelTemplate>
Which when looking at the Visual Tree where the user was clicking the ContentControl, it had a parent of a Canvas that had a ContentPresenter with that top level Canvas such as (see named MainCanvas):
I changed the ContentControl to have a MouseEnter event :
<ContentControl Width="100" Height="100" MouseEnter="EnterMouse">
<Grid>
<Ellipse Fill="Silver">
In that method I needed to find the named "MainCanvas" Canvas and enumerate all of its children the ContentPresenters and extract the max ZIndex and then set my ContentControl (shown in blue above) to that ZIndex value plus 1.
Here is the code behind where extract the necessary the parents:
private void EnterMouse(object sender, MouseEventArgs e)
{
if (sender is ContentControl cc)
{
var cpParent = FindParent<ContentPresenter>(cc);
var p2 = FindParent<Canvas>(cpParent);
var max = p2.Children.Cast<UIElement>().Max(control => Panel.GetZIndex(control));
Panel.SetZIndex(cpParent, max + 1);
}
}
private T FindParent<T>(DependencyObject child) where T : DependencyObject
{
DependencyObject immediateParent = VisualTreeHelper.GetParent(child);
T parent = immediateParent as T;
return parent ?? FindParent<T>(immediateParent);
}
Scenario:
I am working on a Store App in WinRT/Win8.
I have a ScrollView, with a custom UserControl child inside - all as part of one "main" UserControl.
When the main UserControl (with the ScrollView -> child UserControl) in is Initialized/navigated to - even with the App width not full-screen; the UserControl is at the full width of the ScrollView - as desired. Images below:
Image 1 - main User Control Opens with Window Fullscreen
Image 2 - main User Control Opens Starts Half-Width (or any width)
The ScrollView itself is within a Grid and keeps with the full width of the App window, even when it's resized - as desired.
Issue:
The issue I'm having is that when I resize the App window horizontally, the child UserControl does not keep the same width as its parent ScrollView's.
This causes the ScrollView to then have Horizontal Scrollbars - which I do not want.
Image 3 - Window Horizontal Width Resized
I want to keep the width of the child to be bound inside the width of the ScrollView with no Horizontal Scrollbars (as in Image 2).
Markup is similar to this (I have stripped down for readability):
<Grid>
<!-- Some row/column definitions in here -->
...
<!-- A header TextBlock -->
...
<ScrollViewer x:Name="scrlTableRows" Grid.ColumnSpan="3" Grid.Row="1"
HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"
Padding="66,0,66,40" ZoomMode="Disabled">
<local:MyCustomUserControl Margin="0,10,0,10" HorizontalAlignment="Stretch" />
</ScrollViewer>
...
<!-- Just a button here-->
</Grid>
I have already tried setting (on the child custom UserControl):
Width="{Binding Path=ActualWidth, ElementName=scrlTableRows}"
The child is not set at the full width of the ScrollView to start with (which is what I need), and doesn't resize the width with its parent either - giving me scrollbars
Width="{Binding Path=Width, ElementName=scrlTableRows}" The child does start at the full width of the parent, but doesn't resize - giving me scrollbars
I have also tried placing the UserControl inside a Grid (within the ScrollView), amongst many other HorizontalAligment and Width properties.
All to no avail.
No other similar situations/answers have worked from other helpful fellows at StackOverflow.
Obviously, I need the vertical scrollbars - as is kind of evident; before anyone asks.
Can anybody give me any pointers, please?
Update:
Here is the custom UserControl's Xaml, as requested by #LovetoCode:
<UserControl *usual user control declaritive stuff in here*>
<UserControl.Resources>
<CollectionViewSource x:Key="FieldViewModelsSource" Source="{Binding ItemToEdit.FieldViewModels}"/>
<datatemplateselectors:FieldViewModelDataTemplateSelector
x:Key="FieldViewModelDataTemplateSelector"
AudioFieldTemplate="{StaticResource TableRowAudioFieldDataTemplate}"
CheckboxFieldTemplate="{StaticResource TableRowCheckboxFieldDataTemplate}"
DatasetFieldTemplate="{StaticResource TableRowDatasetFieldDataTemplate}"
DateFieldTemplate="{StaticResource TableRowDateFieldDataTemplate}"
DateTimeFieldTemplate="{StaticResource TableRowDateTimeFieldDataTemplate}"
DropdownFieldTemplate="{StaticResource TableRowDropdownFieldDataTemplate}"
FileFieldTemplate="{StaticResource TableRowFileFieldDataTemplate}"
GpsFieldTemplate="{StaticResource TableRowGpsFieldDataTemplate}"
GridFieldTemplate="{StaticResource TableRowGridFieldDataTemplate}"
ImageFieldTemplate="{StaticResource TableRowImageFieldDataTemplate}"
LabelFieldTemplate="{StaticResource TableRowLabelFieldDataTemplate}"
MultichoiceCheckboxFieldTemplate="{StaticResource TableRowMultichoiceCheckboxFieldDataTemplate}"
RadioFieldTemplate="{StaticResource TableRowRadioFieldDataTemplate}"
RangeSliderFieldTemplate="{StaticResource TableRowRangeSliderFieldDataTemplate}"
SignatureFieldTemplate="{StaticResource TableRowSignatureFieldDataTemplate}"
SplitterFieldTemplate="{StaticResource TableRowSplitterFieldDataTemplate}"
TextFieldTemplate="{StaticResource TableRowTextFieldDataTemplate}"
TextareaFieldTemplate="{StaticResource TableRowTextareaFieldDataTemplate}"
TimeFieldTemplate="{StaticResource TableRowTimeFieldDataTemplate}"
VideoFieldTemplate="{StaticResource TableRowVideoFieldDataTemplate}"/>
</UserControl.Resources>
<Grid>
<ItemsControl ItemsSource="{Binding Source={StaticResource FieldViewModelsSource}}"
ItemTemplateSelector="{StaticResource FieldViewModelDataTemplateSelector}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Margin="10,0,10,0" Orientation="Vertical" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Grid>
</UserControl>
Note that the DataTemplate resources in the UserControl resources are custom UserControls that are loaded in based on objects in the ViewModel (like in my original image 1).
So, with great thanks to #LovetoCode, I managed to remedy my issue. Still trying to get over my 2-day headache and bruises from banging my head against the desk, though.
I ditched the ScrollViewer and just used my custom UserControl:
<local:TableRowUserControl Grid.Row="1" Grid.ColumnSpan="2"
Margin="66,0,66,40" HorizontalContentAlignment="Stretch" />
Then, as #LovetoCode suggested - I used a ListView instead of ItemsControl. My most sincere apologies. I didn't want to use one first time round because...
Main issue was with the ListView's default style to have hover and tap effects; which I didn't need. I tried to steer clear of disabling the hover/tap from previous experience of failing - miserably.
After a bit of Googling (other search engines are available), I found a simple solution to do this quite easily.
I managed to do it like this:
<ListView x:Name="lstFieldViewModels" ItemsSource="{Binding Source={StaticResource FieldViewModelsSource}}" SelectionMode="None"
ItemTemplateSelector="{StaticResource FieldViewModelDataTemplateSelector}" IsSwipeEnabled="False">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListViewItem">
<ContentPresenter />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Margin="10,0,10,0" Orientation="Vertical" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
Again, props to #LovetoCode. Gold star and programmer points for you :)
I want to archive a vertical ListView that contains a UserControl in which i have some infos on the left and a second ListView that will scroll horizontal.
The problem is that my second listview will not start to scroll. It seems to pick unlimited space.
First of all some more infos about my setup:
My window is arranged via a grid basically just a row on top with text and the first listview in the second row.
The first listview uses a ItemTamplate like the following:
<ListView.ItemTemplate>
<DataTemplate>
<controls:MyControl />
</DataTemplate>
</ListView.ItemTemplate>
Beside that it has a ItemContainerStyle to display a horizontal line between the items:
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem"
BasedOn="{StaticResource {x:Type ListViewItem}}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListViewItem">
<StackPanel>
<Rectangle x:Name="Separator"
Height="2"
SnapsToDevicePixels="True"
Fill="{DynamicResource AccentColorBrush}" />
<ContentPresenter />
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
(trigger that disables the unnecessary first line omitted)
MyControl is a UserControl which is also just a grid first column some text and second column is my second listview.
This one is special because it is horizontal. Since their are various approaches for this from arround the internet i will show the one i ended using with.
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal"
IsItemsHost="True"
IsVirtualizing="True"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
Item template is again a UserControl (at the moment just a TextBlock) and again the separator lines but this time vertically.
The problem is now that the second ListView is not scrollable. Even if i explicit set them to be visible they are disabled (also after resizing window).
My approach solving this was binding MaxWidth of Stackpanel in ListViewItem Template to Actual with of my MetroWindow.
MaxWidth="{Binding Path=ActualWidth, RelativeSource={RelativeSource AncestorType={x:Type metroControls:MetroWindow}}}"
But this and some other tries binding different sizes of different items does not work.
Can somebody give a hint to resolve this?
Is there any means to set Canvas Children Property without ItemsControl ItemsSource Binding Property?
In order to keep separated my view from viewmodel, I have to bind the items.
I have used the the canvas as a designer from 'CodeProject'
http://www.codeproject.com/KB/WPF/WPFDiagramDesigner_Part2.aspx
I'm using a canvas for drag-and-drop purposes. It works well when I work manually inside the canvas.
Which means I add and remove the child items using
myCanvas.Children.Add(userControl);
myCanvas.Children.Remove(userControl);
But if I load my usercontrols at run time, they are loaded just as views.
<s:Canvas AllowDrop="True" >
<ItemsControl Grid.Row="1" ItemsSource="{Binding Path=userControls}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<s:Canvas Background="Transparent"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<s:ControlItem Content="{Binding Path=MyView}"></s:ControlItem >
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Canvas.Left" Value="{Binding Path=X}" />
<Setter Property="Canvas.Top" Value="{Binding Path=Y}" />
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
</s:Canvas>
No, there aint. (Except manually clearing and adding...)
Ummm yeah just draw items inside the canvas? :)
<Canvas>
<TextBlock Text="I'm Child #1" />
<TextBlock Text="I'm Child #2" Canvas.Top="50" />
</Canvas>
Or you can always do it in code-behind
myCanvas.Children.Add(myTextBlock);
foreach(var someControl in SomeControlList)
myCanvas.Children.Add(someControl);
Edit
I see your update and have no idea what you're asking. If you want to drag/drop items onto a Canvas, you are better off adding/removing items from the ItemsSource than manually adding/removing items from the Canvas. Simply adding/removing them from myCanvas will not update the collection in your ItemsSource
I would recommend taking a look at Bea Stollnitz's article on dragging/dropping databound Items. This means you would keep the ItemsControl you have now, but when you drop an item on top of the Canvas it adds the DataItem behind that object to the ObservableCollection<MyDataItem> that you call userControls (I don't like this name because it suggests that the data items contain UI items, which should not be the case)
I was wondering if its possible to somehow bind a list of lists to a cavas panel. For example having object "layer" which itself is a list of "rectangle" objects. Would if be possible to bind a list of layers to a canvas? So far I can only do it by binding a flattened INumerable of the nested list (using SelectMany function) to an itemcontrol, but this isnt good enough, Id like to keep the "layers" separate and have the Zindex of the rectangles vary according to the layer it is at, allowing to reorder the layers easily.
I have also tried having nested itemcontrols but as expected it only displays the first layer. The aim is to draw a rectangle for every object in every layer on the canvas allowing for layer manipulation, insertion of new objects in each layer, etc...
Thanks in advance! :)
How about making the ItemTemplate of the main ItemsControl another ItemsControl with yet another Canvas as ItemsPanel? (I do not see a reason why it should only display the first layer)
Actually the main ItemsControl does not need to be a Canvas, a Grid would do as well (at least unless your collections have coordinates of their own or a Z-Order, if you use a grid the layer order is he same as their appearance in the collection).
An example (a bit verbose but can't do anything about that):
<ItemsControl ItemsSource="{Binding Data}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding LayerItems}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="{x:Type ContentPresenter}">
<!-- Here would the binding to some properties that take care of placement -->
<Setter Property="Canvas.Top" Value="{Binding Top}" />
<Setter Property="Canvas.Left" Value="{Binding Left}" />
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<!-- Some template for the individual items -->
<DataTemplate>
<Border Padding="5" BorderThickness="1" BorderBrush="Red" CornerRadius="3"
Background="White">
<TextBlock Text="{Binding Name}" />
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Like H.B said, i too can't see a reason why it will not work. Having an ItemsControl in another ItemsContainer works perfectly fine.
<ItemsControl ItemsSource="{Binding Layers}">
<ItemsControl.ItemsContainerStyle>
<Style>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<ItemsControl ItemsSource="{Binding Rectangles}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<ItemsControl.ItemsContainerStyle>
</ItemsControl>
But it think it would be cleaner to put the sub ItemsControl inside an DataTemplate for your Items, without the need to modify the ItemsContainerStyle. I think its bad design if your control needs to know informations about the properties of the model, which is necessary for binding to Rectangles.