C# / WPF Color to Double Conversion - c#

I am attempting to create a WPF program (for practice) that will allow the selection of a color based on three slider bars (red, green, and blue), save (apply) said color based on the rgb values from the slider, to a sample box and a save for later box.
My Problem: I can't figure out how to convert the saved color from the save for later box back into values that can be placed back into the slider values. I can apply the saved color, but it's the values of the saved color that I want. This code compiles and runs until I click and initiate Click_savedColor, then the program freezes.
WPF Code:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel Margin="10" VerticalAlignment="Center">
<DockPanel VerticalAlignment="Center" Margin="10">
<Label DockPanel.Dock="Left" FontWeight="Bold">R:</Label>
<TextBox Text="{Binding ElementName=slColorR, Path=Value, UpdateSourceTrigger=PropertyChanged}" DockPanel.Dock="Right" TextAlignment="Right" Width="40" />
<Slider Name="slColorR" Maximum="255" TickPlacement="BottomRight" TickFrequency="1" IsSnapToTickEnabled="True" ValueChanged="ColorSlider_ValueChanged" />
</DockPanel>
<DockPanel VerticalAlignment="Center" Margin="10">
<Label DockPanel.Dock="Left" FontWeight="Bold">G:</Label>
<TextBox Text="{Binding ElementName=slColorG, Path=Value, UpdateSourceTrigger=PropertyChanged}" DockPanel.Dock="Right" TextAlignment="Right" Width="40" />
<Slider Name="slColorG" Maximum="255" TickPlacement="BottomRight" TickFrequency="1" IsSnapToTickEnabled="True" ValueChanged="ColorSlider_ValueChanged" />
</DockPanel>
<DockPanel VerticalAlignment="Center" Margin="10">
<Label DockPanel.Dock="Left" FontWeight="Bold">B:</Label>
<TextBox Text="{Binding ElementName=slColorB, Path=Value, UpdateSourceTrigger=PropertyChanged}" DockPanel.Dock="Right" TextAlignment="Right" Width="40" />
<Slider Name="slColorB" Maximum="255" TickPlacement="BottomRight" TickFrequency="1" IsSnapToTickEnabled="True" ValueChanged="ColorSlider_ValueChanged" />
</DockPanel>
</StackPanel>
<GridSplitter Name="test" HorizontalAlignment="Center"/>
<Button Name="compColor" Grid.Column="2" Click="Click_compColor"/>
<GridSplitter HorizontalAlignment="Right"/>
<Button Name="savedColor" Grid.Column="3" Click="Click_savedColor"/>
</Grid>
C# Code:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void ColorSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
Color color = Color.FromRgb((byte)slColorR.Value, (byte)slColorG.Value, (byte)slColorB.Value);
compColor.Background = new SolidColorBrush(color);
}
void Click_compColor(object sender, RoutedEventArgs e)
{
savedColor.Background = compColor.Background;
}
void Click_savedColor(object sender, RoutedEventArgs e)
{
bool bools = Convert.ToBoolean(savedColor.Background);
byte[] bytes = BitConverter.GetBytes(bools);
slColorR.Value = Convert.ToDouble(bytes[0]);
slColorG.Value = Convert.ToDouble(bytes[1]);
slColorB.Value = Convert.ToDouble(bytes[2]);
compColor.Background = savedColor.Background;
}
}
Below is an image of the program: First box contains color sliders; second box contains color of color sliders; third box contains saved color from second box.

I'm not understanding how you trying to save you color. But there is Color property in SolidColorBrush, so you can take all color components from that:
var red = savedColor.Background.Color.R;
var green = savedColor.Background.Color.G;
var blue = savedColor.Background.Color.B;

You can do it using Properties, by implementing the INotifyPropertyChanged Interface, and binding Properties to corresponding value sliders. For example:
private int _GreenValue;
private int _RedValue;
private int _BlueValue;
private Color _BackGroundColor;
public int GreenValue
{
get { return _GreenValue; }
set
{
_GreenValue = value;
_BackGroundColor = Color.FromArgb(_RedValue, _GreenValue, _BlueValue);
}
}
public int MyProperty
{
get { return _RedValue; }
set
{
_RedValue = value;
_BackGroundColor = Color.FromArgb(_RedValue, _GreenValue, _BlueValue);
}
}
public int BlueValue
{
get { return _BlueValue; }
set
{
_BlueValue = value;
_BackGroundColor = Color.FromArgb(_RedValue, _GreenValue, _BlueValue);
}
}
public Color BackGroundColor
{
get { return _BackGroundColor; }
}
Where BackGroundColor is a read-only field which will change any of the associated integer value changed.

Related

Listview - Textblock - Button - FolderBrowserDialog - ObservableCollection Binding

I am trying to wrap my head around C#-wpf-MVVM.
I am attempting to put it to use with a simple idea I want to implement
.csv files stores LocationName, Location for default file locations.
.csv is read into a datatable for reference
ObservableCollection is created from datatable
Listview is bound to ObservableCollection
Textblock is bound to SelectedItem.LocationName
Button activates a FileDialogBrowser, the result of which I would like to use to update the location of the SelectedItem.LocationName
I have bound the Listview to the ObservableCollection and bound the Textblock to the SelectedItem.
Where I am running into problems is how do I get the result of the FolderDialogBrowser to update the ObservableCollection SelectedItem.LocationName?
If I change the text manually in the Textblock everything works fine...However, if I use codebehind to update the Textblock...no changes are happening.
private ObservableCollection<FileLocation > _filelocation;
private FileLocation _selectedLocation;
public ObservableCollection<FileLocation > FileLocations
{
get { return _filelocation; }
set
{
_filelocation = value;
OnPropertyChanged("Files");
}
}
public FileLocation SelectedFile
{
get { return _selectedLocation; }
set
{
_selectedLocation = value;
OnPropertyChanged("SelectedFile");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
FileLocations = new ObservableCollection<FileLocation>();
foreach (DataRow row in DtLocations.Rows)
{
string LocationDescription = (string)row.ItemArray[0];
string LocationPath = (string)row.ItemArray[1];
FileLocations.Add(new FileLocation() { LocationName = LocationDescription, Location = LocationPath });
}
<TextBox x:Name="tbxFileLocation" Tag="FileLocation" Grid.Row="1" Grid.Column="4" Width="200" Height="23" Foreground="Black" VerticalContentAlignment="Center" Text ="{Binding SelectedFile.Location ,Mode=TwoWay }" />
<Button x:Name="btnFolderLocator" Content="..." Grid.Row="1" Grid.Column="5" Width="25" Height=" 23" Background="White" HorizontalAlignment="Left" Click="BtnFolderLocator_Click" />
<ListView x:Name="lvwFileLocations" Grid.Row="9" Grid.Column="1" Grid.RowSpan="2" Grid.ColumnSpan="2" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ItemsSource="{Binding FileLocations}" SelectedItem="{Binding SelectedFile }" Margin="0">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="250"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="{Binding Path= LocationName, Mode=TwoWay}"></TextBlock>
<TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Path= Location , Mode=TwoWay}"></TextBlock>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

send data from one window to another c# xaml wpf

i want to send Data from one Textbox on window One to a label on window Two.
starting with window two:
<StackPanel>
<StackPanel x:Name="ButtonStackPanel" Height="Auto" Width="Auto">
<StackPanel Orientation="Horizontal">
<StackPanel Orientation="Vertical">
<Button Style="{DynamicResource ButtonStyle}" Content="To The Dark Side" Click="OnClickToDarkSide"/>
<Button Style="{DynamicResource ButtonStyle}" Content="To The Gray" Click="OnClickToGraySide"/>
<Button Style="{DynamicResource ButtonStyle}" Content="To The Light Side" Click="OnClickToLightSide"/>
</StackPanel>
<Border HorizontalAlignment="Center" VerticalAlignment="Stretch" Background="Red" Height="Auto" Width="2"/>
<Label Style="{DynamicResource LabelStyle}" x:Name="theTextBlock" Content="{Binding Source=CodeText}"/>
<Border HorizontalAlignment="Center" VerticalAlignment="Stretch" Background="Red" Height="Auto" Width="2"/>
<ToggleButton Style="{DynamicResource ToggleButtonStyle}" Content="Open Style Window" Name="StyleWindowButton" Click="OnClickOpenStyleWindow"/>
<ToggleButton Style="{DynamicResource ToggleButtonStyle}" Content="Open Text Window" Name="TextWindowButton" Click="OnClickOpenTextWindow"/>
</StackPanel>
<Border Height="2" Width="Auto" Background="Red" HorizontalAlignment="Stretch" VerticalAlignment="Center"/>
</StackPanel>
<Border Height="2" Width="Auto" Background="Red" HorizontalAlignment="Stretch" VerticalAlignment="Center"/>
</StackPanel>
Codebehind of Window Two:
public MainWindow()
{
(App.Current as App).CodeText = _jediCode;
InitializeComponent();
}
private void OnClickToDarkSide(object sender, RoutedEventArgs e)
{
(App.Current as App).ChangeSkin(Skin.Dark);
(App.Current as App).CodeText = _sithCode;
theTextBlock.Content = (App.Current as App).CodeText;
}
private void OnClickToLightSide(object sender, RoutedEventArgs e)
{
(App.Current as App).ChangeSkin(Skin.Light);
(App.Current as App).CodeText = _jediCode;
theTextBlock.Content = (App.Current as App).CodeText;
}
private void OnClickToGraySide(object sender, RoutedEventArgs e)
{
(App.Current as App).ChangeSkin(Skin.Gray);
(App.Current as App).CodeText = _grayCode;
theTextBlock.Content = (App.Current as App).CodeText;
}
private void OnClickOpenStyleWindow(object sender, RoutedEventArgs e)
{
if (StyleWindowButton.IsChecked == true)
{
styleWindow = new StyleWindow();
styleWindow.Show();
}
else
{
styleWindow.Close();
styleWindow = null;
}
}
private void OnClickOpenTextWindow(object sender, RoutedEventArgs e)
{
if (TextWindowButton.IsChecked == true)
{
textWindow = new InputWindow();
textWindow.Show();
}
else
{
textWindow.Close();
textWindow = null;
}
}
}
window one:
<Grid>
<TextBox HorizontalAlignment="Left" VerticalAlignment="Top" Height="200" Width="200" TextWrapping="Wrap"
AcceptsReturn="True" AcceptsTab="True" Text="{Binding Path=CodeText, Source={x:Static Application.Current}, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" Margin="10,10,0,0">
<!-- TODO: trigger change from this textbox to the textblock in mainwindow -->
</TextBox>
</Grid>
code behind of one is empty.
app.xaml.cs:
public string CodeText
{
get => _codeText;
set { _codeText = value; OnPropertyChanged(nameof(CodeText)); }
}
Ok, the current behavior is clicking on one of the buttons (Dark Side, Gray, Light Side) leads to changes in the CodeText Property, which leads to a change of the content of the label of Window Two and the text of TextBox of Window One. Changing the text of the TextBox, changes also the CodeText Property, but does not lead to a change in the label and thats confusing, why does it work the one way, but not the other.
hope you have a hint for me. :) Maybe i missed a trigger or a kind of refresh for the label
bindings in window One and Two are set differently. (window Two does it wrong, Content="{Binding Source=CodeText}" is not valid binding)
in fact, window Two removes the binding by assigning CodeText directly as local value:
theTextBlock.Content = (App.Current as App).CodeText;
you should remove that line, and use the same binding as in window One:
<Label Style="{DynamicResource LabelStyle}" x:Name="theTextBlock"
Content="{Binding Path=CodeText, Source={x:Static Application.Current}}"/>

How to make a StackPanel visible only when the DragCompleted + Condition is matched

I am working on a UWP app in which my requirement is to show a StackPanel only when Drag is completed in a grid view and condition is met too.
I am making a drag and re-order like game. I want the StackPanel (Containing Result and Buttons) appear when not only a single drag is completed but all the items are sorted too.
I have got everything else working fine. Only StackPanel is problem. It appears just after on drag completed whether the condition is met or not.
Following are the screenshots, code and more briefing !
ScreenShot
XAML for GridView
<GridView Name="GameDisplay"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Grid.Row="1"
Grid.Column="1"
CanDrag="True"
CanDragItems="True"
CanReorderItems="True"
SelectionMode="Single"
AllowDrop="True"
DragItemsCompleted="GameDisplay_DragItemsCompleted">
<GridView.ItemTemplate>
<DataTemplate>
<Grid Width="60"
Height="60"
Background="Black">
<TextBlock Text="{Binding}"
FontFamily="BriLliant"
FontSize="48"
FontWeight="light"
Foreground="White"
TextAlignment="Center"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsWrapGrid Orientation="Horizontal"
MaximumRowsOrColumns="10"/>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
</GridView>
XAML For StackPanel
<StackPanel Grid.Row="1" Grid.Column="1" Name="GameFinished" Background="#9900ff" Width="800" HorizontalAlignment="Center" VerticalAlignment="Center" Height="auto">
<Grid Name="InnerGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="4*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel Name="BtnsContainer" Grid.Column="1" Width="auto" Height="auto" Margin="0 10 0 0">
<Grid Name="BtnsGrid">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Name="txtBannerType"
Width="auto"
Height="auto"
Grid.Row="0"
Text="Well Done !"
FontSize="72"
FontWeight="Bold"
FontFamily="BriLliant"
Foreground="White"
TextAlignment="Center"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
<TextBlock Name="txtTimeSpent"
Width="200"
Height="auto"
Grid.Row="1"
Text=""
FontSize="48"
FontWeight="Light"
FontFamily="BriLliant"
Foreground="White"
TextAlignment="Center"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
<TextBlock Name="txtScore"
Width="200"
Height="auto"
Grid.Row="2"
Text="Score : 0"
FontSize="48"
FontWeight="Light"
FontFamily="BriLliant"
Foreground="White"
TextAlignment="Center"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
<TextBlock Name="txtBestScore"
Width="200"
Height="auto"
Grid.Row="3"
Text="Best Score : 0"
FontSize="48"
FontWeight="Light"
FontFamily="BriLliant"
Foreground="White"
TextAlignment="Center"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
<Button Name="RestartGame"
Width="200"
Height="70"
Grid.Row="4"
Background="Black"
Content="Restart"
FontSize="48"
FontWeight="Bold"
FontFamily="BriLliant"
Foreground="White"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Margin="0 20 0 0"
Click="RestartGame_Click"/>
<Button Name="MainMenu"
Width="200"
Height="70"
Grid.Row="5"
Background="Black"
Content="Main Menu"
FontSize="48"
FontWeight="Bold"
FontFamily="BriLliant"
Foreground="White"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Margin="0 20 0 0"
Click="MainMenu_Click"/>
</Grid>
</StackPanel>
</Grid>
</StackPanel>
C# Events
private void Page_Loaded(object sender, RoutedEventArgs e)
{
lib.New(GameDisplay);//For Starting New Game
}
private void GameDisplay_DragItemsCompleted(ListViewBase sender, DragItemsCompletedEventArgs args)
{
lib.completed(GameDisplay);//When the tiles are re-ordered
}
Class that is handling BackEnd
class Library
{
//BackEnd for Math Game
private const int size = 5;
private const int total = size * size;
private DateTime timer;
private ObservableCollection<int> items = new ObservableCollection<int>();
private Random random = new Random((int)DateTime.Now.Ticks);
public void show(string content, string title)
{
IAsyncOperation<IUICommand> command = new MessageDialog(content, title).ShowAsync();
}
private List<int> select(int start, int finish, int total)
{
int number;
List<int> numbers = new List<int>();
while ((numbers.Count < total))
{
number = random.Next(start, finish + 1);
if ((!numbers.Contains(number)) || (numbers.Count < 1))
{
numbers.Add(number);
}
}
return numbers;
}
private bool winner()
{
return items.OrderBy(o => o).ToList().SequenceEqual(items.ToList());
}
private void layout(ref GridView grid)
{
timer = DateTime.UtcNow;
grid.IsEnabled = true;
grid.ItemsSource = null;
items = new ObservableCollection<int>();
List<int> numbers = select(1, total, total);
int index = 0;
while (index < numbers.Count)
{
items.Add(numbers[index]);
index++;
}
grid.ItemsSource = items;
}
public void New(GridView grid)
{
layout(ref grid);
}
public void completed(GridView grid)
{
string congo = "";
if (winner())
{
TimeSpan duration = (DateTime.UtcNow - timer).Duration();
congo = string.Format("Time: {0}:{1}:{2}", duration.Hours, duration.Minutes, duration.Seconds);
grid.IsEnabled = false;
}
}
}
Above is the game screen. When I drag and re-order a tile an event is fired in which a method runs until all the tiles are dragged and reordered according to the index of list that is containing all these numbers.
StackPanel only waits for one Drag. Is there any way to add StackPanel into the condition that checks for list sort?? Something like Data-Binding??
If you find anything missing, wrong or the question is already solved before. Please let me know explicitly !
Thanks...
Since you have already use winner() method to judge whether the game is ended and also invoke this in GameDisplay_DragItemsCompleted method. So actually the condition is already met in your completed method (every drag completed to judge whether game is over ). We just need to set the Visibility property of StackPanel to visible.
Update complete method as follows:
public void completed(GridView grid,StackPanel stackpanel)
{
string congo = "";
if (winner())
{
TimeSpan duration = (DateTime.UtcNow - timer).Duration();
congo = string.Format("Time: {0}:{1}:{2}", duration.Hours, duration.Minutes, duration.Seconds);
grid.IsEnabled = false;
stackpanel.Visibility = Visibility.Visible;
}
}
Update GameDisplay_DragItemsCompleted method as follows:
private void GameDisplay_DragItemsCompleted(ListViewBase sender, DragItemsCompletedEventArgs args)
{
lib.completed(GameDisplay,GameFinished);//When the tiles are re-ordered
}
Pay attention that in default the StackPanel should be collapsed. Update XAML code about StackPanel as follows:
<StackPanel Grid.Row="1" Grid.Column="1" Name="GameFinished" Background="#9900ff" Width="800" HorizontalAlignment="Center" VerticalAlignment="Center" Height="auto" Visibility="Collapsed">
And you can reset the state for StackPanel and GridView when game restart. Code as follows:
private void RestartGame_Click(object sender, RoutedEventArgs e)
{
GameDisplay.IsEnabled = true;
GameFinished.Visibility = Visibility.Collapsed;
}
And the result:
The problem is, by this code in winner function
return items.OrderBy(o => o).ToList().SequenceEqual(items.ToList()); }
You just check if list items is equal to list items. It will always return true.
According to this msdn document orderBy orders the list itself does not return a copy of it.
If you are going to use this method, create another list to compare with curent list and keep that list sorted.
You may create two bool flags and check them in both methods OnDragComplete and OnChangeCondition like this:
private void OnDragComplete()
{
_isDragCompleted = true;
if (_isDragCompleted && _isConditionChanged)
{
CollapseStackPanel();
}
}
private void OnChangeCondition()
{
_isConditionChanged = true;
if (_isDragCompleted && _isConditionChanged)
{
CollapseStackPanel();
}
}
private void CollapseStackPanel()
{
_isDragCompleted = false;
_isConditionChanged = false;
StackPanel.Visibility = Visibility.Collapsed;
}

Photo and description on Flipview

I have a flipview which contains photos and descriptions. I want when photo1 be tapped, then descbox1 not visible. And if photo1 be tapped again, then descbox1 will appear.
XAML:
<FlipView x:Name="narrowFlipview"
ItemsSource="{Binding Group.Items}"
SelectedItem="{Binding Item, Mode=TwoWay}"
Foreground="{x:Null}"
Visibility="Collapsed">
<FlipView.ItemTemplate>
<DataTemplate>
<Grid x:Name="content1"
Margin="0,0,0,0">
<Image x:Name="photo1"
Margin="0,0,10,10"
Source="{Binding ImagePath}"
Tapped="photo_Tapped" />
<Grid x:Name="detail"
VerticalAlignment="Bottom"
Height="200">
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<Button x:Name="hideBtn"
Height="50"
Width="50"
Margin="0,0,5,0"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Grid.Row="0"
Click="hideBtn_Click">
<Button.Background>
<ImageBrush Stretch="Uniform"
ImageSource="images/media/ikon-56-app-white-down.png" />
</Button.Background>
</Button>
<Button x:Name="detailBtn"
Height="50"
Width="50"
Margin="0,0,5,0"
HorizontalAlignment="Right"
VerticalContentAlignment="Bottom"
Grid.Row="1"
Visibility="Collapsed"
Click="detailBtn_Click">
<Button.Background>
<ImageBrush Stretch="Uniform"
ImageSource="images/media/ikon-56-app-white-up.png" />
</Button.Background>
</Button>
<ScrollViewer x:Name="descBox1"
Grid.Row="1"
Height="150"
Background="#95000000"
VerticalScrollBarVisibility="Auto">
<TextBlock x:Name="descriptionText1"
Text="{Binding Description}"
Margin="20,20,20,0"
TextWrapping="Wrap"
TextAlignment="Justify"
VerticalAlignment="Top"
Height="auto"
Foreground="White"
FontSize="21" />
</ScrollViewer>
</Grid>
</Grid>
</DataTemplate>
</FlipView.ItemTemplate>
</FlipView>
I tried using the code below:
private DependencyObject FindChildControl<T>(DependencyObject control, string ctrlName)
{
int childNumber = VisualTreeHelper.GetChildrenCount(control);
for (int i = 0; i < childNumber; i++)
{
DependencyObject child = VisualTreeHelper.GetChild(control, i);
FrameworkElement fe = child as FrameworkElement;
// Not a framework element or is null
if (fe == null) return null;
if (child is T && fe.Name == ctrlName)
{
// Found the control so return
return child;
}
else
{
// Not found it - search children
DependencyObject nextLevel = FindChildControl<T>(child, ctrlName);
if (nextLevel != null)
return nextLevel;
}
}
return null;
}
public bool _IsOn;
public bool IsOn
{
get
{
return _IsOn;
}
set
{
_IsOn = value;
}
}
private void photo_Tapped(object sender, TappedRoutedEventArgs e)
{
ScrollViewer descBox1 = FindChildControl<ScrollViewer>(this, "descBox1") as ScrollViewer;
Button hideBtn = FindChildControl<Button>(this, "hideBtn") as Button;
Button detailBtn = FindChildControl<Button>(this, "detaiBtn") as Button;
IsOn = !IsOn;
if (_IsOn)
{
descBox1.Visibility = Visibility.Collapsed;
hideBtn.Visibility = Visibility.Collapsed;
detailBtn.Visibility = Visibility.Visible;
}
else
{
descBox1.Visibility = Visibility.Visible;
hideBtn.Visibility = Visibility.Visible;
detailBtn.Visibility = Visibility.Collapsed;
}
}
But when I tap photo1, descBox1 would not collapse, hiddenBtn would not collapsed, detailBtn would not visible.
How to handle it?
According to your requirement, I'd think using Binding here to control these control's visibility would be a simpler solution. For example, we can take advantage of the Tag property.
Ref Remarks in FrameworkElement.Tag property:
The scenario for the Tag property is to provide an general-purpose property on all FrameworkElement classes that supports data binding, animation and styles for itself but where the property's value does not have any implicit meaning to platform subsystems like layout, app model, text, input and so on.
Here we can use this property to store the Visibility and in other controls, bind ther Visibility property to this property like:
<ScrollViewer x:Name="descBox1"
Grid.Row="1"
Height="150"
Background="#95000000"
VerticalScrollBarVisibility="Auto"
Visibility="{Binding Tag, ElementName=photo1}">
<TextBlock x:Name="descriptionText1"
Height="auto"
Margin="20,20,20,0"
VerticalAlignment="Top"
FontSize="21"
Foreground="White"
Text="{Binding Description}"
TextAlignment="Justify"
TextWrapping="Wrap" />
</ScrollViewer>
Then in photo_Tapped method, we can change Tag's value to control the visibility of "descBox1".
private void photo_Tapped(object sender, TappedRoutedEventArgs e)
{
var tag = (sender as Image)?.Tag?.ToString();
//if we didn't set Tag in Image, its value should be null and descBox1 will be Visible
if (string.IsNullOrEmpty(tag) || tag.Equals("Visible"))
{
(sender as Image).Tag = Visibility.Collapsed;
}
else
{
(sender as Image).Tag = Visibility.Visible;
}
}
"hiddenBtn" is similar, we only need to set the Mode of the Binding to TwoMay, so that when we change its visibility, "descBox1" and "detailBtn" will also change their visibility automatically.
<Button x:Name="hideBtn"
Grid.Row="0"
Width="50"
Height="50"
Margin="0,0,5,0"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Click="hideBtn_Click"
Visibility="{Binding Tag, ElementName=photo1, Mode=TwoWay}">
<Button.Background>
<ImageBrush ImageSource="images/media/ikon-56-app-white-down.png" Stretch="Uniform" />
</Button.Background>
</Button>
private void hideBtn_Click(object sender, RoutedEventArgs e)
{
ChangeButtonVisibility(sender);
}
private void ChangeButtonVisibility(object sender)
{
var visibility = (sender as Button)?.Visibility;
if (visibility.Equals(Visibility.Visible))
{
(sender as Button).Visibility = Visibility.Collapsed;
}
else
{
(sender as Button).Visibility = Visibility.Visible;
}
}
"detailBtn" is the same as "hiddenBtn", but its visibility is opposite to "hiddenBtn". So we will need a InvertedVisibilityConverter like following:
public class InvertedVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
return InvertedVisibility(value);
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
return InvertedVisibility(value);
}
private object InvertedVisibility(object value)
{
var visibility = value?.ToString();
if (string.IsNullOrEmpty(visibility) || visibility.Equals("Visible"))
{
return Visibility.Collapsed;
}
else
{
return Visibility.Visible;
}
}
}
And in "detailBtn", setting Binding like following:
<Button x:Name="detailBtn"
Grid.Row="1"
Width="50"
Height="50"
Margin="0,0,5,0"
HorizontalAlignment="Right"
VerticalContentAlignment="Bottom"
Click="detailBtn_Click"
Visibility="{Binding Tag, ElementName=photo1, Mode=TwoWay, Converter={StaticResource InvertedVisibilityConverter}}">
<Button.Background>
<ImageBrush ImageSource="images/media/ikon-56-app-white-up.png" Stretch="Uniform" />
</Button.Background>
</Button>
private void detailBtn_Click(object sender, RoutedEventArgs e)
{
ChangeButtonVisibility(sender);
}
Update: To make the visibilities in all FlipViewItems have the same behavior, we need a dependence property that can store the visibility "globally". So we can use FlipView's Tag property instead of Image's Tag property and in Image set the Binding like following:
<Image x:Name="photo1"
Margin="0,0,10,10"
Source="{Binding ImagePath}"
Tag="{Binding Tag, ElementName=narrowFlipview, Mode=TwoWay}"
Tapped="photo_Tapped" />
After this all Image's Tag will have the same value. And as this is a two-way binding, when we change one Image's Tag value, it will automatically change FlipView.Tag's value and then propagate to all other Images.
In other controls like "descBox1", "hiddenBtn" and "detailBtn", we can also change their Binding by change ElementName from photo1 to narrowFlipview. Using "detailBtn" for example:
<Button x:Name="detailBtn"
Grid.Row="1"
Width="50"
Height="50"
Margin="0,0,5,0"
HorizontalAlignment="Right"
VerticalContentAlignment="Bottom"
Click="detailBtn_Click"
Visibility="{Binding Tag, ElementName=narrowFlipview, Mode=TwoWay, Converter={StaticResource InvertedVisibilityConverter}}">
<Button.Background>
<ImageBrush ImageSource="images/media/ikon-56-app-white-up.png" Stretch="Uniform" />
</Button.Background>
</Button>
And there is no need to change the code-behind, after editing the Bindings in XAML, it should be able to achieve what you want.

Mouse scroll not working in a scroll viewer with a wpf datagrid and additional UI elements

I am trying to figure out how to get the mouse scroll working on a wpf window with a scrollviewer and a datagrid within it. The WPF and C# code is below
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Border Name="DataGridBorder" BorderThickness="2" Margin="1" CornerRadius="4" BorderBrush="#FF080757">
<dg:DataGrid AutoGenerateColumns="False" Name="ValuesDataGrid"
BorderThickness="0" CanUserResizeColumns="True" FontWeight="Bold" HorizontalScrollBarVisibility="Auto"
CanUserReorderColumns="False" IsReadOnly="True" IsTextSearchEnabled="True" AlternationCount="2"
SelectionMode="Extended" GridLinesVisibility="All"
HeadersVisibility="Column" CanUserAddRows="False" CanUserDeleteRows="False" CanUserResizeRows="False" CanUserSortColumns="False"
RowDetailsVisibilityMode="Collapsed" SelectedIndex="0"
RowStyle="{StaticResource CognitiDataGridRowStyle}"
>
<dg:DataGrid.Columns>
<dg:DataGridTemplateColumn Header="Title" >
<dg:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" >
<TextBlock HorizontalAlignment="Left" VerticalAlignment="Center" Text="{Binding Path=Name}" FontWeight="Normal" />
</StackPanel>
</DataTemplate>
</dg:DataGridTemplateColumn.CellTemplate>
</dg:DataGridTemplateColumn>
</dg:DataGrid.Columns>
</dg:DataGrid>
</Border>
</Grid>
<Button Grid.Row="1" Height="90" >hello world</Button>
</Grid>
</ScrollViewer>
and the C# code is as follows
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
initialize();
}
public void initialize()
{
ObservableCollection<MyObject> testList = new ObservableCollection<MyObject>();
for (int i = 0; i < 20; i++)
{
MyObject my = new MyObject("jack " + i);
testList.Add(my);
}
ValuesDataGrid.ItemsSource = testList;
}
}
public class MyObject
{
public string Name { get; set; }
public MyObject(string name)
{
Name = name;
}
}
The problem i am facing is that when using the mouse to scroll, it works fine when it is over the button but as soon as i move the mouse pointer over the grid and try to scroll, nothing happens. I am able to move the scrollbar of the scrollviewer directly though. I am still a wpf novice so any help on how to get the mouse scroll to work over the datagrid would be appreciated. I am guessing there should be a pretty easy solution for this but I havent been able to figure it out
I think Dave's solution is a good one. However, one recommendation I'd make is to catch the PreviewMouseWheel event on the scrollviewer instead of on the datagrid. If you don't, you might notice some minor differences based on whether you're scrolling over the datagrid or the scroll bar itself. The reasoning is that the scrollviewer will be handling scrolling when the mouse is hovered over the scrollbar, and the datagrid event will handle the scrolling when over the datagrid. For instance, one mouse wheel scroll over the datagrid might bring you farther down your list then it would when over the scroll bar. If you catch it on scrollviewer preview event, all will use the same measurement when scrolling. Also, if you catch it this way, you won't need to name the scrollviewer element, as you won't need a reference to the object since you can just type cast the sender object passed into the scrollviewer PreviewMouseWheel event. Lastly, I'd recommend marking the event handled at the end of the event, unless you need to catch it in an element further down the heirarchy for some reason. Example below:
private void ScrollViewer_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
ScrollViewer scv = (ScrollViewer)sender;
scv.ScrollToVerticalOffset(scv.VerticalOffset - e.Delta);
e.Handled = true;
}
I'm assuming the DataGrid does not need to scroll - Set the VerticalScrollBar="None" on the DataGrid.
The DataGrid swallows the mouse scroll event.
What I found is to use the PreviewMouseWheel event to scroll the container that you want to scroll. You will need to name the scrollviewer to change the Vertical offset.
private void DataGrid_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset-e.Delta);
}
An improvement to Don B's solution is to avoid using ScrollToVerticalOffset.
scv.ScrollToVerticalOffset(scv.VerticalOffset - e.Delta);
VerticalOffset - Delta results in a pretty jarring experience. The ScrollViewer puts a lot of thought into making the movement smoother than that. I think it also scales the delta down based on dpi and other factors...
I found it's better to catch and handle the PreviewMouseWheelEvent and send a MouseWheelEvent to the intended ScrollViewer. My version of Don B's solution looks like this.
private void ScrollViewer_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
var eventArg = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta);
eventArg.RoutedEvent = UIElement.MouseWheelEvent;
eventArg.Source = e.Source;
ScrollViewer scv = (ScrollViewer)sender;
scv.RaiseEvent(eventArg);
e.Handled = true;
}
To enable touch support you might also want to set ScrollViewer.PanningMode to None on your DataGrid and set the same property to VerticalFirst or other value on your top level ScrollViewer
Example
<ScrollViewer VerticalScrollBarVisibility="Auto" Margin="5" PanningMode="VerticalFirst">
<DataGrid ScrollViewer.PanningMode="None" ItemsSource="{Binding Items}" />
</ScrollViewer>
Of course, also use the PreviewMouseWheel event as indicated by Don B's answers to fix the original mouse scrolling issue.
private static void ScrollViewer_PreviewMouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
{
var scrollViewer = (ScrollViewer)sender;
scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset - e.Delta);
e.Handled = true;
}
Or, you can simply set the following Attached Property to your ScrollViewer
public class TopMouseScrollPriorityBehavior
{
public static bool GetTopMouseScrollPriority(ScrollViewer obj)
{
return (bool)obj.GetValue(TopMouseScrollPriorityProperty);
}
public static void SetTopMouseScrollPriority(ScrollViewer obj, bool value)
{
obj.SetValue(TopMouseScrollPriorityProperty, value);
}
public static readonly DependencyProperty TopMouseScrollPriorityProperty =
DependencyProperty.RegisterAttached("TopMouseScrollPriority", typeof(bool), typeof(TopMouseScrollPriorityBehavior), new PropertyMetadata(false, OnPropertyChanged));
private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var scrollViewer = d as ScrollViewer;
if (scrollViewer == null)
throw new InvalidOperationException($"{nameof(TopMouseScrollPriorityBehavior)}.{nameof(TopMouseScrollPriorityProperty)} can only be applied to controls of type {nameof(ScrollViewer)}");
if (e.NewValue == e.OldValue)
return;
if ((bool)e.NewValue)
scrollViewer.PreviewMouseWheel += ScrollViewer_PreviewMouseWheel;
else
scrollViewer.PreviewMouseWheel -= ScrollViewer_PreviewMouseWheel;
}
private static void ScrollViewer_PreviewMouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
{
var scrollViewer = (ScrollViewer)sender;
scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset - e.Delta);
e.Handled = true;
}
}
Usage
<ScrollViewer b:TopMouseScrollPriorityBehavior.TopMouseScrollPriority="True" VerticalScrollBarVisibility="Auto" Margin="5" PanningMode="VerticalFirst">
<DataGrid ScrollViewer.PanningMode="None" ItemsSource="{Binding Items}" />
</ScrollViewer>
Where b: is the namespace that contains this behavior
This way your no code-behind is needed and your app is purely MVVM
I tried Don B's solution and it's solves the issue with scrolling over a data grid pretty well for the cases when you don't have other inner scrollable controls.
For the case when the scroll viewer has as children other scrollable controls and a data grid, then that requires that the event shouldn't be marked as handled at the end of the event handler for the main scroll viewer so it could be catched also in the inner scrollable controls, however that has the side effect that when the scroll should occur only on the inner scrollable control, it will also occur on the main scroll viewer.
So I've updated Dave's solution with the difference for how the scroll viewer is found so it won't be necessary to know the name of the scroll viewer:
private void DataGrid_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
ScrollViewer scrollViewer = (((DependencyObject)sender).GetVisualParent<ScrollViewer>());
scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset - e.Delta);
}
#fjch1997, I used your solution and it works pretty well.
There is only one problem which I found. It's connected with the comment of #Vadim Tofan:
For the case when the scroll viewer has as children other scrollable
controls and a data grid, then that requires that the event shouldn't
be marked as handled at the end of the event handler for the main
scroll viewer so it could be catched also in the inner scrollable
controls, however that has the side effect that when the scroll should
occur only on the inner scrollable control, it will also occur on the
main scroll viewer.
I also tried to remove e.Handled = true statement, but then the effect is not nice - both scrolls are moved in the same time. So, finally I enhanced a little bit event handler method to the following one:
private static void ScrollViewer_PreviewMouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
{
ScrollViewer scrollViewer = (ScrollViewer)sender;
FrameworkElement origicalControlSender = e.OriginalSource as FrameworkElement;
ScrollViewer closestScrollViewer = origicalControlSender.GetParent<ScrollViewer>();
if (closestScrollViewer != null && !ReferenceEquals(closestScrollViewer, scrollViewer))
{
return;
}
scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset - e.Delta);
e.Handled = true;
}
public static T GetParent<T>(this FrameworkElement control)
where T : DependencyObject
{
FrameworkElement parentElement = control?.Parent as FrameworkElement;
if (parentElement == null)
{
return null;
}
T parent = parentElement as T;
if (parent != null)
{
return parent;
}
return GetParent<T>(parentElement);
}
This now prevents the outside scroller to scroll in case inner ScrollViewer exists.
Guys I`ve seen most of the solution posted over here and fundamentally all of them are right, but I think there is an easiest and more elegant syntax that we could apply.
Assuming that we don't need to scroll with our data grid and instead we would like to scroll with our MainWindow
fallowing "Dave" and "Vladim Tofan" answer
Private Void Scrlll(Object sebder, MouseWheelEventArgs e)
{
var windows = (Window.GetWindow(this) as MainWindow).MainScroll;
windows.ScrollToVerticalOffset(windows.VerticalOffset - e.Delta);
}
Sorry, for bad english.
Here is a larger example of creating a WPF behavior that scrolls the DataGrid.
First define the following base class for gluing together framework element with behavior class and its behavior implementation.
using System.Diagnostics.CodeAnalysis;
using System.Windows;
using System.Windows.Input;
namespace SomeAcme.Client.Infrastructure
{
/// <summary>
/// Behavior handler class for creating WPF behaviors.
/// </summary>
[ExcludeFromCodeCoverage]
public class BehaviorHandler<TAssociatedObject, TBehaviorClass>
where TAssociatedObject: DependencyObject
where TBehaviorClass : class, IAssociationBehavior, new()
{
public BehaviorHandler()
{
}
public static TBehaviorClass GetBehavior(DependencyObject obj)
{
if (obj == null)
return null;
return (TBehaviorClass)obj.GetValue(BehaviorProperty);
}
public static void SetBehavior(DependencyObject obj, TBehaviorClass value)
{
if (obj != null)
{
obj.SetValue(BehaviorProperty, value);
}
}
// Using a DependencyProperty as the backing store for Behavior. This enables animation, styling, binding, etc...
public static readonly DependencyProperty BehaviorProperty =
DependencyProperty.RegisterAttached("Behavior", typeof(TBehaviorClass), typeof(object), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits));
public void FindOrCreateBehaviorOnDemand(DependencyObject dependencyObject)
{
//Apply the behavior
TBehaviorClass behavior = FindOrCreateBehavior(dependencyObject);
if (behavior != null)
{
dependencyObject.SetValue(BehaviorProperty, behavior);
}
}
public TBehaviorClass FindOrCreateBehavior(DependencyObject dependencyObject)
{
if (dependencyObject == null)
return null;
var associatedObject = dependencyObject;
if (associatedObject == null)
return null;
var behavior = dependencyObject.GetValue(BehaviorProperty) as TBehaviorClass;
if (behavior == null)
{
var behaviorAssociated = new TBehaviorClass();
if (behaviorAssociated == null)
return null;
behaviorAssociated.InitializeAssociation(associatedObject, AssociatedCommands);
return behaviorAssociated;
}
else
{
return behavior;
}
} //TBehaviorClass FindOrCreateBehavior
/// <summary>
/// Set the associated commands to pass into the WPF behavior, if desired
/// </summary>
public ICommand[] AssociatedCommands { get; set; }
}
}
This looks a bit more complex, but it simplifies boiler plate coding when it comes to gluing together the behavior class with the framework element. In this particular case we will not need to use an associated command.
Our scroll viewer behavior then looks like this:
using SomeAcme.Client.Infrastructure;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace SomeAcme.Client.Infrastructure
{
public static class ScrollViewerMouseWheelScrollBehavior
{
public static string GetUseMouseScrollForScrollViewer(DependencyObject obj)
{
if (obj != null)
{
return (string)obj.GetValue(UseMouseScrollForScrollViewerProperty);
}
else
return null;
}
public static void SetUseMouseScrollForScrollViewer(DependencyObject obj, string value)
{
if (obj != null)
{
obj.SetValue(UseMouseScrollForScrollViewerProperty, value);
}
}
public static readonly DependencyProperty UseMouseScrollForScrollViewerCommandProperty =
DependencyProperty.RegisterAttached("UseScrollForScrollViewer", typeof(string), typeof(ScrollViewerMouseWheelScrollBehavior),
new PropertyMetadata(new PropertyChangedCallback(OnUseScrollForScrollViewerSet)));
public static void OnUseScrollForScrollViewerSet(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs eventArgs)
{
bool useScroll;
bool.TryParse(eventArgs.NewValue?.ToString(), out useScroll);
if (useScroll)
{
var behaviorHandler =
new BehaviorHandler<ScrollViewer, ScrollViewerMouseScrollBehaviorImplementation>();
//behaviorHandler.AssociatedCommands =
// new Microsoft.Practices.Prism.Commands.DelegateCommand<object>[] { (Microsoft.Practices.Prism.Commands.DelegateCommand<object>)eventArgs.NewValue };
behaviorHandler.FindOrCreateBehaviorOnDemand(dependencyObject);
}
}
}
}
namespace SomeAcme.Client.Infrastructure
{
public class ScrollViewerMouseScrollBehaviorImplementation : IAssociationBehavior
{
public void InitializeAssociation(DependencyObject associatedObject, params ICommand[] commands)
{
//TODO: Add commands to associate
var scrollViewer = associatedObject as ScrollViewer;
if (scrollViewer != null)
{
scrollViewer.PreviewMouseWheel += ScrollViewer_PreviewMouseWheel;
}
}
private void ScrollViewer_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
var scrollViewer = sender as ScrollViewer;
if (scrollViewer != null)
{
scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset - e.Delta);
}
}
}
}
In XAML we then can first define the namespaces:
xmlns:local="clr-namespace:SomeAcme.Client.Infrastructure"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Finally we are ready to use the mouse wheel scroll by using the WPF behavior in the XAML.
..
<TabControl Grid.Row="1">
<TabItem Header="Skjemafelter">
<ScrollViewer Height="700" local:ScrollViewerMouseWheelScrollBehavior.UseMouseScrollForScrollViewer="{x:Static sys:Boolean.TrueString}">
<ListView x:Name="ColumnsListView" ItemsSource="{Binding CurrentFields}">
<ListView.View>
<GridView>
I have tested and verified that this approach works. For developers working with a WPF app, utilizing WPF behaviors keeps amount of code in code behind still to the minimum bits and staying faitfully to the MVVM approach.
The Grid has a built in ScrollPanel so wrapping it with a ScrollPanel didn't work at all for me (making the Grid of fixed height was out of the question because I wanted it to resize nicely with the rest of the application).
What I did was a combination of a few of the higher rated solutions in here, but essentially the idea is to get rid of the ScrollPanel and just pipe the PreviewMouseEvent of the DataGrid back to the parent control that is actually handling the scrolling (in my case it was a Grid).
private void DataGrid_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
MouseWheelEventArgs eventArg = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta)
{
RoutedEvent = MouseWheelEvent, Source = e.Source
};
DependencyObject parent = VisualTreeHelper.GetParent((DependencyObject) sender);
while (parent != null && !(parent is Grid))
{
parent = VisualTreeHelper.GetParent(parent);
}
if (parent != null)
{
Grid grid = (Grid) parent;
grid.RaiseEvent(eventArg);
}
e.Handled = true;
}
I found this: http://wpfthoughts.blogspot.com/2014/05/datagrid-vertical-scrolling-issues.html and thought I should add it here.
"If you are targeting Framework 4.5 there is a new dependency object on the DataGrid's internal VirtualizingPanel called ScrollUnit that can be set to Item (the default) or Pixel. If we modify the XAML a little we can see how it works."
<DataGrid Name="DG" ItemsSource="{Binding B0}" AutoGenerateColumns="False" IsReadOnly="true" RowDetailsVisibilityMode="Visible" Width="200"
Height="100" VirtualizingPanel.ScrollUnit="Pixel">
I know it's been a while, but I met the same issue and solved it with DockPanel
<DockPanel Grid.ColumnSpan="3" LastChildFill="True">
<Button DockPanel.Dock="Top" Content="Add" Grid.Column="3" HorizontalAlignment="Right" Width="110" Height="30" Margin="5"/>
<DataGrid x:Name="xxDG" SelectionUnit="Cell" ItemsSource="{Binding}" Margin="0, 0, 0, 0" >
...
</DataGrid>
</DockPanel>
For some reason this handles the mouse wheel events like a charm.
I found that ScrollViewer can't be concatenated, which means if it is concatenated like in your case the Grid starts under the ScrollViewer tag and in the Grid we have DataGrid and in the DataGrid again the ScrollViewer property has been set. i.e.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="45" />
<RowDefinition Height="100*" />
<RowDefinition Height="105" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Grid.Row="0"
Grid.Column="0"
Margin="10,0,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
FontWeight="Bold"
Content="Vessel: " />
<TextBox Height="30"
Width="300"
Margin="70,0,0,0"
HorizontalAlignment="Left"
BorderThickness="1,1,1,1"
IsReadOnly="True"
Name="txtVessel" />
<Label Grid.Row="0"
Grid.Column="2"
Margin="0,0,185,0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
FontWeight="Bold"
Content="Month:" />
<StackPanel Orientation="Horizontal"
Grid.Row="0"
Grid.Column="2"
Margin="0,0,0,0"
HorizontalAlignment="Right">
<ComboBox BorderThickness="2"
HorizontalAlignment="Right"
Name="CmbMonth"
VerticalAlignment="Center"
Width="90" />
<ComboBox BorderThickness="2"
HorizontalAlignment="Right"
Margin="5,0,0,0"
Name="CmbYear"
VerticalAlignment="Center"
Width="90" />
</StackPanel>
<Grid Grid.Row="1"
Grid.ColumnSpan="2">
<Grid.RowDefinitions>
<RowDefinition Height="45" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="30" />
<ColumnDefinition Width="220" />
<ColumnDefinition Width="80" />
<ColumnDefinition Width="80" />
<ColumnDefinition Width="80" />
<ColumnDefinition Width="80" />
<ColumnDefinition Width="120" />
<ColumnDefinition Width="120" />
<ColumnDefinition Width="140*" />
</Grid.ColumnDefinitions>
<Border BorderBrush="Black"
BorderThickness="0,1,1,1"
Grid.Row="0"
Grid.Column="0" />
<Border BorderBrush="Black"
BorderThickness="0,1,1,1"
Grid.Row="0"
Grid.Column="1" />
<Border BorderBrush="Black"
BorderThickness="0,1,1,1"
Grid.Row="0"
Grid.Column="2" />
<Border BorderBrush="Black"
BorderThickness="0,1,1,1"
Grid.Row="0"
Grid.Column="3" />
<Border BorderBrush="Black"
BorderThickness="0,1,1,1"
Grid.Row="0"
Grid.Column="4" />
<Border BorderBrush="Black"
BorderThickness="0,1,1,1"
Grid.Row="0"
Grid.Column="5" />
<Border BorderBrush="Black"
BorderThickness="0,1,1,1"
Grid.Row="0"
Grid.Column="6" />
<Border BorderBrush="Black"
BorderThickness="0,1,1,1"
Grid.Row="0"
Grid.Column="7" />
<Border BorderBrush="Black"
BorderThickness="0,1,1,1"
Grid.Row="0"
Grid.Column="8" />
<Label Grid.Row="0"
Grid.Column="1"
Margin="0,0,0,0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontWeight="Bold"
Content="Item" />
<Label Grid.Row="0"
Grid.Column="2"
Margin="0,0,0,0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontWeight="Bold"
Content="Maker" />
<Label Grid.Row="0"
Grid.Column="3"
Margin="0,0,0,0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontWeight="Bold"
Content="Model" />
<Label Grid.Row="0"
Grid.Column="4"
Margin="0,0,0,0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontWeight="Bold"
Content=" Part No.
Serial No." />
<Label Grid.Row="0"
Grid.Column="5"
Margin="0,0,0,0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontWeight="Bold"
Content="Condition" />
<Label Grid.Row="0"
Grid.Column="6"
Margin="0,0,0,0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontWeight="Bold"
Content=" Onboard
Calibr/Test" />
<Label Grid.Row="0"
Grid.Column="7"
Margin="0,0,0,0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontWeight="Bold"
Content=" Shore
Callibration" />
<Label Grid.Row="0"
Grid.Column="8"
Margin="0,0,0,0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontWeight="Bold"
Content="Remarks" />
</Grid>
<Border Grid.Row="2"
Grid.ColumnSpan="2">
<ScrollViewer Grid.Row="2"
Grid.ColumnSpan="2"
CanContentScroll="True"
HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Auto"
Name="ScrollViewer3"
Margin="0,0,0,0">
<Grid Name="grdOnBoardCalibrationRecord"
Margin="0,0,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="30"></ColumnDefinition>
<ColumnDefinition Width="220"></ColumnDefinition>
<ColumnDefinition Width="80"></ColumnDefinition>
<ColumnDefinition Width="80"></ColumnDefinition>
<ColumnDefinition Width="80"></ColumnDefinition>
<ColumnDefinition Width="80"></ColumnDefinition>
<ColumnDefinition Width="120"></ColumnDefinition>
<ColumnDefinition Width="120"></ColumnDefinition>
<ColumnDefinition Width="140*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Border Grid.Column="0"
BorderThickness="1,0,1,1"
BorderBrush="Black"
Grid.RowSpan="26"></Border>
<Border Grid.Column="1"
BorderThickness="0,1,1,1"
Grid.RowSpan="26"></Border>
<Border Grid.Column="2"
BorderThickness="0,1,1,1"
Grid.RowSpan="26"></Border>
<Border Grid.Column="3"
BorderThickness="0,1,1,1"
Grid.RowSpan="26"></Border>
<Border Grid.Column="4"
BorderThickness="0,1,1,1"
Grid.RowSpan="26"></Border>
<Border Grid.Column="5"
BorderThickness="0,1,1,1"
Grid.RowSpan="26"></Border>
<Border Grid.Column="6"
BorderThickness="0,1,1,1"
Grid.RowSpan="26"></Border>
<Border Grid.Column="7"
BorderThickness="0,1,1,1"
Grid.RowSpan="26"></Border>
<Border Grid.Column="8"
BorderThickness="0,1,1,1"
Grid.RowSpan="26"></Border>
</Grid>
</ScrollViewer>
</Border>
<Grid Grid.Row="3"
Grid.ColumnSpan="2">
<Grid.RowDefinitions>
<RowDefinition Height="30"></RowDefinition>
<RowDefinition Height="30"></RowDefinition>
<RowDefinition Height="40"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBox Grid.Row="0"
Grid.Column="0"
Height="30"
Width="300"
TextAlignment="Center"
Background="Gray"
IsReadOnly="True"
Margin="0,0,0,0"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
BorderThickness="1,1,1,1"
Name="txtChiefEngineer" />
<Label Grid.Row="1"
Grid.Column="1"
Margin="0,0,100,0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
FontWeight="Bold"
Content="Chief Engineer" />
<StackPanel Orientation="Horizontal"
Grid.Row="2"
Margin="0,0,0,0">
<Label Name="lblonshorecomment"
Content=" Shore Comment : "
HorizontalAlignment="Center"
Margin="5,0,0,0"
FontWeight="Bold"
VerticalAlignment="Center"
FontFamily="Calibri"
FontStyle="Normal"
FontSize="14"></Label>
<TextBox BorderThickness="1"
FontWeight="Normal"
IsReadOnly="True"
Height="44"
Width="878"
TextWrapping="Wrap"
AcceptsReturn="True"
HorizontalAlignment="left"
Margin="0,0,0,0"
Name="txtShoreComment"
VerticalAlignment="Center" />
</StackPanel>
</Grid>
</Grid>

Categories

Resources