I have this DataGrid and this Canvas:
<DataGrid Canvas.ZIndex="1" x:Name="dgTimeline"/>
<Canvas Height="30" Width="999" Canvas.ZIndex="2" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="71,387,0,0">
<Line Name="time" X1="0" Y1="0" X2="0" Y2="24" Stroke="Black" StrokeThickness="2"/>
</Canvas>
Which results in:
However, when I move the horizontal scroll bar of the DataGrid the Canvas obviously stays on its position because its parent is the Window and not the DataGrid:
Is it possible to keep Canvas' position relative to the DataGrid instead of its parent in such a way that when scrolling the DataGrid the Canvas would stay stationary as it was a DataGrid's element? I tried to put the Canvas inside of the DataGrid but that didn't work.
You can add horizontal scrollbar to canvas and then try to synchronize the horizontal scrolls of canvas and datagrid. something like ...
private void dataGrid_ScrollChanged(object sender, ScrollChangedEventArgs e)
{
canvasScrollViewer.ScrollToHorizontalOffset(e.HorizontalOffset);
}
private void canvasScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
{
ScrollViewer dgScrollViewer = GetScrollViewerInstance();
dgScrollViewer.ScrollToHorizontalOffset(e.HorizontalOffset);
}
private ScrollViewer GetScrollViewerInstance()
{
var ctrl = VisualTreeHelper.GetChild(dataGrid, 0);
if (ctrl is Border)
{
var ctrl1 = VisualTreeHelper.GetChild(ctrl, 0);
if (ctrl1 is ScrollViewer)
{
dgScrollViewer = ctrl1 as ScrollViewer;
}
}
}
This code is just to give you an idea of how to do it and not a actual working code. You set the HorizontalScrollBarVisibility for Canvas to Hidden if you don't want to show it. You will not need the second event handler in that case.
Related
I use MediaElement and (Time)Slider to play and control playing of a video.
I used answer 2 to this question as a base.
In addition to the dragging capability I would also like the slider thumb to be moved to a mouse click point.
This works ok when the MediaElement and (Time)Slider are paused, but when the video is playing a mouse click has no effect
Here is my code
XAML:
<MediaElement Source="..."
Name="mediaView"
Height="450" LoadedBehavior="Manual" UnloadedBehavior="Stop" Stretch="UniformToFill"
MediaOpened="OnMediaOpened" MediaEnded="OnMediaEnded" MediaFailed="OnMediaFailed" Grid.Row="0" Grid.Column="0"/>
<Grid Name="mediaBar" VerticalAlignment="Bottom" Margin="5,10,5,0" Background="#B2282828" Grid.Row="0" Grid.Column="0">
<!-- ... -->
<Slider Name="timeSlider" Margin="5,5,5,0"
Thumb.DragStarted="OnDragStarted" Thumb.DragCompleted="OnDragCompleted" ValueChanged="OnTimeSliderValueChanged"
PreviewMouseLeftButtonUp="OnMouseLeftButtonUp" IsMoveToPointEnabled="True"
MinWidth="200" FlowDirection="LeftToRight"
Grid.Column="4" Cursor="ScrollWE" VerticalAlignment="Center"/>
<!-- ... -->
</Grid>
relevant c# part:
private void OnDragStarted(object sender, DragStartedEventArgs args)
{
isDragging = true;
ticks.Stop();
}
private void OnDragCompleted(object sender, DragCompletedEventArgs args)
{
isDragging = false;
int SliderValue = (int)timeSlider.Value;
TimeSpan ts = new TimeSpan(0, 0, 0, 0, SliderValue);
mediaView.Position = ts;
if(currentStatus == Status.PLAYING)
ticks.Start();
}
private void OnMouseLeftButtonUp(object sender, EventArgs ea)
{
if(!isDragging)
{
mediaView.Pause();
ticks.Stop();
int SliderValue = (int)timeSlider.Value; // when video is playing this not the point of the mouse click
// ...
}
}
I can understand that timeSlider.Value delivers the current point in time instead of the mouse click position when the video is playing.
Is there another way to measure the position of the mouse click and update the slider value with that ?
Or a better solution for the Mouse-click-while-slider-is-running-situation ?
Try this:
private void OnMouseLeftButtonUp(object sender, MouseButtonEventArgs ea)
{
mediaView.Position = TimeSpan.FromSeconds((int)(mediaView.NaturalDuration.TimeSpan.TotalSeconds * (double)(ea.GetPosition(timeSlider).X / this.Width)));
}
I want to get the Grid control that is wrapped in a border (no Name is assigned), the structure look like this:
<Grid x:Name="main">
<uc:myUc/>
<Border>
<!--other elements-->
</Border>
<Border>
<Grid x:Name="myGrid">
<!--I want to get all controls here-->
</Grid>
</Border>
</Grid>
myUc is a user control that has a button that when clicked, I want to get all the controls inside the grid myGrid:
this is the code I 'm using, it seems I should give a Name to the container Border to be able to get its children, but this is a huge change in my application.
var parent = VisualTreeHelper.GetParent(this) as UIElement;
var grid = (parent as Grid);
var chldrn = grid.Children;
foreach (var item in chldrn)
{
var child = item;
}
//I stopped here!
Is there a way to find all descendants of an element to determie which control I take?
You can access any kind of child in containers by their type
XAML Example:
<Grid x:Name="myGrid">
<Button Content="Button1"></Button>
<Button Content="Button2"></Button>
<CheckBox Content="CheckBox1"></CheckBox>
</Grid>
C# Example
private void Button_Click(object sender, RoutedEventArgs e)
{
foreach(var Child in myGrid.Children.OfType<Button>()) // this will only get buttons in grid's children
{
MessageBox.Show(Child.Content);
}
//another way:
foreach(var Child in myGrid.Children)
{
if (Child is CheckBox)
{
var checkBox = (CheckBox)Child;
checkBox.IsChecked = true;
}
}
}
I have an image and I am updating its position on the canvas as the mouse moves.
<Popup Name="floatingTip" AllowsTransparency="True" Placement="Relative"
PlacementTarget="{Binding ElementName=MainCanvas}">
<Image Source="{Binding Name}"
Width="{Binding Width}"
Height="{Binding Height}"/>
</Popup>
When the mouse enters the canvas I disable the cursor:
private void Canvas_MouseEnter(object sender, MouseEventArgs e)
{
Mouse.OverrideCursor = Cursors.None;
}
While the cursor is moving inside the canvas I update the position of the popup, which contains an image:
private void Canvas_MouseMove(object sender, MouseEventArgs e)
{
if (!floatingTip.IsOpen && currentTool == "staticBrush")
{
floatingTip.IsOpen = true;
}
if (currentTool == "staticBrush" && lvDataBinding.SelectedIndex != -1)
{
Point currentPos = e.GetPosition(this);
floatingTip.HorizontalOffset = currentPos.X - (cursorImage.Width / 2.0);
floatingTip.VerticalOffset = currentPos.Y - (cursorImage.Height / 2.0);
cursorImage.Width = 50;
cursorImage.Height = 50;
}
}
And when the mouse leaves the canvas I set the cursor back to Cursors.Arror.
Everything works fine if the image is not underneath the cursor, that is, if I offset the images position a bit. But if I place the image directly underneath the cursor, the image begins flickering with the arrow cursor (even though the cursor is hidden).
I figured it out. I needed to set IsHitTestVisible to false on the image.
I have a image inside a canvas. When a UserControl loaded, image move up.
<Canvas x:Name="cnvMain" Width="300" VerticalAlignment="Center" Height="200" SnapsToDevicePixels="True">
<Image x:Name="Image1" Width="200" Stretch="None" Canvas.Bottom="0" Source="ImageGallery/Desert.jpg" ></Image>
</Canvas>
I used DoubleAnimation.
DoubleAnimation _Animation;
private Storyboard _StoryBoard;
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
_Animation = new DoubleAnimation();
_Animation.From = -Image1.ActualHeight;
_Animation.To = cnvMain.ActualHeight;
_Animation.RepeatBehavior = RepeatBehavior.Forever;
_Animation.Duration = new Duration(TimeSpan.Parse("0:0:10"));
_Animation.FillBehavior = FillBehavior.Stop;
Storyboard.SetTarget(_Animation, Image1);
Storyboard.SetTargetProperty(_Animation, new PropertyPath(Canvas.BottomProperty));
_StoryBoard = new Storyboard();
_StoryBoard.Children.Add(_Animation);
_StoryBoard.Begin();
}
This code work well. My problem is the canvas did not overlay around of image like a frame (Image size is bigger of canvas and I want area of image inside canvas viewed). When I change Canvas to Grid it overlay outside of image but the animation did not work.
Try and use ClipToBounds="True" on your Canvas:
I have a Canvas that contains a button which I want to be able to drag and drop into another canvas. I want to copy the button to the other Canvas. Here is the code I am using:
The XAML:
<Window>
<Grid>
<Canvas
Height="300"
Width="500"
Background="Gray">
<Canvas
Name="cnvToolBox"
Canvas.Left="10"
Canvas.Top="10"
Background="AliceBlue"
Width="100"
Height="200">
<Button
Content="Drag Me!"
PreviewMouseLeftButtonDown="Button_PreviewMouseLeftButtonDown"
PreviewMouseMove="Button_PreviewMouseMove"></Button>
</Canvas>
<Rectangle
Canvas.Left="119"
Canvas.Top="9"
Width="102"
Height="202"
StrokeDashArray="0.5 1.0 0.3"
Stroke="Black"
StrokeThickness="2"/>
<Canvas
Name="cnvButtonDropZone"
Canvas.Left="120"
Canvas.Top="10"
Width="100"
Height="200"
Background="LightGreen"
AllowDrop="True"
DragEnter="Canvas_DragEnter"
Drop="Canvas_Drop">
</Canvas>
</Canvas>
</Grid>
</Window>
Here's the Code Behind:
public partial class MainWindow : Window
{
private Point startPoint;
public MainWindow()
{
InitializeComponent();
}
private void Button_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
startPoint = e.GetPosition(null);
}
private void Button_PreviewMouseMove(object sender, MouseEventArgs e)
{
Point currentPosition = e.GetPosition(null);
Vector diff = startPoint - currentPosition;
if (e.LeftButton == MouseButtonState.Pressed &&
(Math.Abs(diff.X) > SystemParameters.MinimumHorizontalDragDistance ||
Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance))
{
Button button = sender as Button;
DataObject dragData = new DataObject("myFormat", button);
DragDrop.DoDragDrop(button, dragData, DragDropEffects.Copy);
}
}
private void Canvas_DragEnter(object sender, DragEventArgs e)
{
if (!e.Data.GetDataPresent("myFormat") || sender == e.Source)
{
e.Effects = DragDropEffects.None;
}
}
private void Canvas_Drop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent("myFormat"))
{
Button button = e.Data.GetData("myFormat") as Button;
Canvas canvas = sender as Canvas;
canvas.Children.Add(button);
}
}
}
When I drop the button I get the following exception when I'm adding the button to the canvas:
Specified element is already the logical child of another element. Disconnect it first.
I'm just trying to learn how to drag and drop controls and not really sure what that error means and how to resolve it. I don't know where I'm going wrong. Any suggestions would be welcome.
Thanks!
The button is owned by its parent cnvToolBox. You need to remove it from cnvToolBox before adding it to the canvas.
cnvToolBox.Children.Remove(button);
var canvas = sender as Canvas;
canvas.Children.Add(button);
This moves the button from your toolbox to the canvas. If you actually want to clone the item you want something like:
if (e.Data.GetDataPresent("myFormat"))
{
var contentControl = (ContentControl)e.Data.GetData("myFormat");
var constructorInfo = contentControl.GetType().GetConstructor(new Type[] {});
if (constructorInfo != null)
{
var newElement = (UIElement)constructorInfo.Invoke(new object[]{});
var newContentControl = newElement as ContentControl;
if(newContentControl != null)
{
newContentControl.Content = contentControl.Content;
}
((Panel)sender).Children.Add(newElement);
}
}
It's because the Button already has a parent associated with it; the previous Canvas.
You can set the parent of the Button to null; which will essentially remove it from the logical relationship.
button.Parent = null;
You will then be able to add that Button to another Canvas as you have done in your code behind.
You can also remove the Button from the Children property directly if you prefer and then add it accordingly within the new Canvas.
Canvas.Children.Remove(button);