I am trying to make a custom color picker which inherit from ComboBox.
This is the screenshot.
As you can see, it's just a very normal color picker interface.
So far, almost everything is fine except the problem I write in the screenshot.
I can drag the spectrum slider, RGBA sliders and click those 2 buttons without problem.
If I click on empty space inside the ComboBoxItem, the popup disppears, this is also the behavior I need and it works.
Here are the codes of the canvas area.
XAML
<Canvas x:Name="colorPlatte" Width="175" Height="150" Grid.Row="0" Grid.Column="0" Margin="4" MouseLeftButtonDown="colorPlatte_MouseLeftButtonDown" MouseLeftButtonUp="colorPlatte_MouseLeftButtonUp" MouseMove="colorPlatte_MouseMove">
<Rectangle x:Name="ColorShadingRectangle"
Height="{Binding ElementName=colorPlatte, Path=Height}"
Width="{Binding ElementName=colorPlatte, Path=Width}"
Fill="{Binding ElementName=sliderSpectrum, Path=SelectedColor, Converter={StaticResource ColorToSolidBrush}}"/>
<Rectangle x:Name="WhiteGradient" Width="{Binding ElementName=colorPlatte,Path=Width}" Height="{Binding ElementName=colorPlatte,Path=Height}">
<Rectangle.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
<GradientStop Offset="0" Color="#ffffffff" />
<GradientStop Offset="1" Color="Transparent" />
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<Rectangle x:Name="BlackGradient" Width="{Binding ElementName=colorPlatte,Path=Width}" Height="{Binding ElementName=colorPlatte,Path=Height}">
<Rectangle.Fill>
<LinearGradientBrush StartPoint="0,1" EndPoint="0, 0">
<GradientStop Offset="0" Color="#ff000000" />
<GradientStop Offset="1" Color="#00000000" />
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<Canvas x:Name="colorSelector" Width="12" Height="12" IsHitTestVisible="False">
<Ellipse Width="12" Height="12" StrokeThickness="3" Stroke="#FFFFFFFF" IsHitTestVisible="False" />
<Ellipse Width="12" Height="12" StrokeThickness="1" Stroke="#FF000000" IsHitTestVisible="False" />
</Canvas>
</Canvas>
Code-behind related to the canvas
private void colorPlatte_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Point p = e.GetPosition(colorPlatte);
UpdateColorSelectorPosColor(p);
colorPlatte.CaptureMouse();
}
private void colorPlatte_MouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
Point p = e.GetPosition(colorPlatte);
UpdateColorSelectorPosColor(p);
Mouse.Synchronize();
}
}
private void colorPlatte_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
colorPlatte.ReleaseMouseCapture();
}
So, how should I prevent the popup close after user drags the color selector?
Thanks.
Edit : 12/6
Sorry for not descript my question clearly and miss lead you, the previous screenshot was taken in design mode directly and might ignore too much.
I should not say inherit from ComboBox, the ColorPicker is actually an UserControl, and I place it in baseComboBoxItem(inherit from ComboBoxItem) which under a baseComboBox(inherit from ComboBox)
When user click the ComboBox, only one item in popup(the ColorPicker) for user to choose color.
But if user drag the color selector(please refer to previous screenshot), it cause the ComboBox popup(dropdown?) closed automatically.
My question is how should I do to stay the popup open after user drag the color selector(after user trigger MouseLeftButtonUp event)?
I think that if you want to do that (and use a combobox) you have to set the whole template of the combobox (described here), and in the popup set StayOpen to True.
But, as HighCore commented, you don't really need a combobx.
You should have a ToggleButton, and When it's Checked set the canvas visibility to visible, and when it's not checked set the canvas visibility to collapsed
Related
I have a control with a button and scrollviewer next to it. I want to be able to change keyboard focus via arrow keys or the tab key. I've set scrollviewer's focusable to true, but it seems it still cannot gain focus via keyboard. If I click on the scrollviewer then I can scroll using the arrow keys (up/down), but I cannot actually navigate to it without using the mouse.
I can focus on the button fine and if I change the scrollviewer for another control (in the same position) such as ScrollContentPresenter then the other control can switch focus between itself and the button as I would expect.
I am trying to understand why ScrollViewer cannot gain focus here. All search results I have found have the reverse problem (ScrollViewer stealing focus). Also if I set focusable to true on a control inside the ScrollViewer then it can gain focus as well. It just seems to be impossible for ScrollViewer to gain focus.
Here's the code sample with commented out ScrollContentPresenter (which can gain focus when used to replace ScrollViewer).
<Grid >
<StackPanel Orientation="Horizontal">
<Button Height="50" Width="300" Style="{StaticResource ButtonStyleLol}" />
<ScrollViewer Height="200" Width="1300" Focusable="True">
<StackPanel Height="1000" >
<StackPanel.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="Black"/>
<GradientStop Color="#FFF71E1E" Offset="1"/>
</LinearGradientBrush>
</StackPanel.Background>
</StackPanel>
</ScrollViewer>
<!--<ScrollContentPresenter Height="200" Width="1300" Focusable="True">
<ScrollContentPresenter.Content>
<StackPanel Height="1000">
<StackPanel.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="Black"/>
<GradientStop Color="#FFF71E1E" Offset="1"/>
</LinearGradientBrush>
</StackPanel.Background>
</StackPanel>
</ScrollContentPresenter.Content>
</ScrollContentPresenter>-->
</StackPanel>
</Grid>
Setting the IsTabStop property of the ScrollViewer to true seems to work for me:
<ScrollViewer IsTabStop="True" Focusable="True">
I have a common popup in my wpf window and I have a button in the datagrid as well. What I want is to open the popup when the button is clicked. The popup should be independent to each button click. For example, let's say that I have two rows in the datagrid. When I click on the first button popup should appear,then I do some changes to that popup and close it. Now I click the second button it should open a new popup instead of the changes I made before. I'm using a common popup for this. Please anyone tell me is it possible to handle my requirement with common popup window?
XAML
<Popup x:Name="popUpServer" IsOpen="False" Placement="MousePoint" >
<Border Background="#FFEFF2F3" BorderBrush="Black" BorderThickness="1" Width="229" Height="145">
<StackPanel Orientation="Horizontal" Margin="0,0,0,-17">
<Grid Width="227" Margin="0,0,0,10">
<GroupBox Header="Configuration" HorizontalAlignment="Left" Margin="9,6,-9,0" VerticalAlignment="Top" Height="125" Width="211">
<Grid>
<Label Content="Auto Restart" HorizontalAlignment="Left" Margin="10,6,0,0" VerticalAlignment="Top"/>
<ToggleSwitch:HorizontalToggleSwitch x:Name="tsAutoRestart" HorizontalAlignment="Left" Margin="97,10,0,0" VerticalAlignment="Top" Width="46" ThumbSize="22" Height="21" RenderTransformOrigin="3.522,1.048">
<ToggleSwitch:HorizontalToggleSwitch.UncheckedBackground>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFC80000" Offset="1"/>
<GradientStop Color="#FF0A0A0A" Offset="0.853"/>
</LinearGradientBrush>
</ToggleSwitch:HorizontalToggleSwitch.UncheckedBackground>
<ToggleSwitch:HorizontalToggleSwitch.CheckedBackground>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#000000" />
<GradientStop Color="#000000" Offset="1" />
</LinearGradientBrush>
</ToggleSwitch:HorizontalToggleSwitch.CheckedBackground>
<ToggleSwitch:HorizontalToggleSwitch.ThumbBrush>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFD6D4D4" />
<GradientStop Color="#FFD6D4D4" Offset="1" />
<GradientStop Color="#FFD6D4D4" Offset="0.02" />
</LinearGradientBrush>
</ToggleSwitch:HorizontalToggleSwitch.ThumbBrush>
</ToggleSwitch:HorizontalToggleSwitch>
<ComboBox x:Name="cbDuration" HorizontalAlignment="Left" VerticalAlignment="Top" Width="92" Margin="97,40,0,0">
<ComboBoxItem Content="30 Minutes"/>
<ComboBoxItem Content="1 Hours"/>
<ComboBoxItem Content="2 Hours"/>
</ComboBox>
<Label Content="After" HorizontalAlignment="Left" VerticalAlignment="Top" Width="83" Margin="9,36,0,0"/>
<Button x:Name="btnApply" Content="Apply" HorizontalAlignment="Left" Margin="125,75,0,0" VerticalAlignment="Top" Width="64" Click="BtnApply_Click"/>
</Grid>
</GroupBox>
</Grid>
</StackPanel>
</Border>
</Popup>
Datagrid
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<Button x:Name="txtServerInfo" Click="TxtServerInfo_Click" Height="23" Width="28">
<Button.Background>
<ImageBrush ImageSource="img.png"/>
</Button.Background>
</Button>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Code behind file
private void TxtServerInfo_Click(object sender, RoutedEventArgs e)
{
popUpServer.IsOpen = true;
}
If you want to use a common popup means better create a popup in a separate user control.then for a button click you can create a new object for the user control and then open the popup by using the user controls object.then the values inside the popup will be independent of the previous button click.
please try the next solution; combine your popup with the button into a separate user control, in that way you can trigger the popup opening based on the button click, and for each button click there will be it's(button) own popup opened there. When you combine the popup and the button together they will have the same data context, thus you will have no problem to make a binding, from the other hand if you want a different data contexts for these controls you can support the user with two dependency properties form that a combined user control.
I'll glad to help if you will have problems with the code, let me know about that.
Regards.
<Menu Height="50" Margin="0,0,0,0" HorizontalAlignment="Stretch" FlowDirection="RightToLeft">
<Menu.Background>
<LinearGradientBrush EndPoint="0,0" StartPoint="0,1">
<GradientStop Color="#FFB3DDF2" Offset="1.0"/>
<GradientStop Color="#FFD6E9F4" Offset="0.0"/>
</LinearGradientBrush>
</Menu.Background>
</Menu>
This Menu will stretch no matter how long the page is and doesn't need to have a width.
<Menu Width="350" Margin="0,0,0,0" VerticalAlignment="Stretch" HorizontalAlignment="Left" FlowDirection="RightToLeft" DockPanel.Dock="Bottom">
<Menu.Background>
<LinearGradientBrush EndPoint="0,0" StartPoint="0,1">
<GradientStop Color="#FFD6E9F4" Offset="1.0"/>
<GradientStop Color="White" Offset="0.0"/>
</LinearGradientBrush>
</Menu.Background>
</Menu>
I want to do the same with this menu however it requires a height which means if i stretch the page down, the menu size will not stretch with the page. When I don't put a height into the code no menu bar appears. My question is how come I don't need a width for the menu bar but i need a height.
Thanks in advance
It is by design.
A menu bar is something that is assumed to stretch across the control it is contained in. That's why it doesn't need a width.
It needs a height because you can put any content inside it.
A stretch height wouldn't have a whole lot of meaning for a menu control, since it'd just be a large blank area of its background color, if WPF were to draw it for you.
Is it somehow possible to have somekind of a blurred border when scrolling? For better understanding I added a picture of what I want to acchieve.
The restriction that I have is, that underneath the ScrollViewer I have got a background Image. Thus, I cant just use a filled Rectangle with white to transparent gradient at the left side of the ScrollViewer.
Since WinRT dropped support for OpacityMask and I'm not sure if you'd want to set it with an Alpha channel. With that said though, there's pretty much always a work around. So what if you just utilize the natural z-order instead and fake it? Something like this;
<!-- Grid as Container -->
<Grid>
<ScrollViewer VerticalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Visible">
<!-- example backgrounds, like images, just for the concept example. -->
<StackPanel Orientation="Horizontal">
<Rectangle Height="75" Width="300" Fill="Red" Margin="20,0"/>
<Rectangle Height="75" Width="300" Fill="Red" Margin="20,0"/>
<Rectangle Height="75" Width="300" Fill="Red" Margin="20,0"/>
<Rectangle Height="75" Width="300" Fill="Red" Margin="20,0"/>
<Rectangle Height="75" Width="300" Fill="Red" Margin="20,0"/>
</StackPanel>
</ScrollViewer>
<!-- An adhoc gradient overlay to just float over the ScrollViewer itself.
Then using Margin to fit it to the shape of the Scrollviewer and still
allow hit visibility to the scrollbar etc. -->
<Rectangle Width="50" HorizontalAlignment="Left" Margin="1,1,0,20">
<Rectangle.Fill>
<LinearGradientBrush EndPoint="1,0.5" StartPoint="0.1,0.5">
<GradientStop Color="White" Offset="0.3"/>
<GradientStop Color="Transparent" Offset="1"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
</Grid>
Of course you'll probably want to tweak some values like the Rectangle Margin in the example to make it look exactly right with your own setup, but the concept should be there and is an option. Hope this helps.
I'm working on a very eye-candy program and I'm required to add a reflection and a 3D depth to the controls.
On both cases I need to paint the control a couple of times, but with changes:
For the reflection I'll have to repaint the control again at the bottom + flip it.
And as for the 3D depth, it's just a lot of copies behind + to the side.
The question is how can I get the image of the control in order to modify it and paint it below / behind it? Do you have any caveats and warnings / helpful tips regarding such actions? (I've never tried anything similar before).
Many thanks.
In WPF you can use a VisualBrush as the background/fill of another element (such as a Rectangle). This VisualBrush has a Visual property that can be bound to another control in order to mimic its content. Using transforms and alpha masks on this control can help apply reflection-style effects. For example:
<StackPanel Width="200">
<TextBox x:Name="tb">Hello world</TextBox>
<Rectangle Height="40" HorizontalAlignment="Stretch">
<Rectangle.Fill>
<VisualBrush Visual="{Binding ElementName=tb}" />
</Rectangle.Fill>
<Rectangle.RenderTransform>
<ScaleTransform CenterY="20" ScaleY="-1" />
</Rectangle.RenderTransform>
<Rectangle.OpacityMask>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="#00000000" Offset="0" />
<GradientStop Color="#FFFFFFFF" Offset="1" />
</LinearGradientBrush>
</Rectangle.OpacityMask>
</Rectangle>
</StackPanel>