Я хочу создать элемент управления, охватывающий всю область, кроме определенной области. Эта конкретная область будет иметь форму эллипса / прямоугольника. Что-то вроде концепции ниже
Моя идея - использовать пути. Ниже мой код пути.
<Path Name = "ShowcasePath" StrokeThickness = "1" IsHitTestVisible = "True">
<Path.Data>
<GeometryGroup>
<EllipseGeometry RadiusX = "100" RadiusY = "50"/>
<RectangleGeometry/>
</GeometryGroup>
</Path.Data>
</Path>
CentreEllipseGeometry и RectRectangleGeometry будут установлены в коде позади.
У этого метода есть две проблемы
Есть идеи по решению вышеуказанных проблем?
или какие-нибудь другие идеи для этого элемента управления?
@RonBeyer Окончательный цвет будет прозрачным белым.
Я понимаю, что это всего лишь макет того, что вы хотите охватить, на него просто трудно смотреть (по крайней мере, на моем ЖК-дисплее). Может быть, лучшим вариантом было бы привязать Visibility всего остального, чтобы все, кроме того, что вы хотите показать, было скрыто?
@RonBeyer Нет, все элементы управления должны быть видны через полупрозрачный белый цвет. Поэтому я не могу настроить Visibility на это.
Свяжите все элементы управления (кроме того, который вы хотите сохранить активным) свойство IsEnabled, а затем при необходимости установите для него значение False. Удачного кодирования :)
@zackraiyan Я хочу создать CustomControl, который будет стоять поверх всех остальных элементов управления. Так что это невозможно. Кроме того, установка IsEnabled изменит внешний вид элемента управления.
Если вы настроите шаблон элементов управления (я знаю, что это немного обходной путь), тогда вы можете избавиться от проблемы с неактивным изменением внешнего вида ...
@zackraiyan Я думаю, вы не поняли сути. Этот элемент управления может что угодно (например, Grid, GridView, Button, RadioButton). Мой настраиваемый элемент управления должен перекрывать все элементы управления, кроме выделенного элемента управления. Все остальные элементы управления должны быть неактивными.
Я не знаю, возможно ли это с помощью customControl или нет (возможно, это так), но единственный способ, который приходит на ум, - это форма с обратной формой, которая выходит только из обведенной области. :(
В этом сценарии вы столкнетесь с парой ошибок. Во-первых, если родительская панель, на которой размещено ваше наложение, не останется фиксированного размера, наличие настраиваемого пути только исказит вашу открытую область, поэтому вывод будет непредсказуемым, если вы вручную не создадите данные пути на лету. Клип здесь не вариант. Кроме того, есть предостережение о том, что базовые элементы UIElements будут по-прежнему доступны для вкладок / действий, даже если вы не можете щелкнуть их, если вы также не справитесь с этим. Однако вы можете проявить творческий подход к своему порядку DOM и дать ИЛЛЮЗИЮ этого эффекта без какого-либо беспорядка, если вам нужен пример.
@ChrisW. Я буду менять данные пути на лету. Я не понял второй проблемы. Также, возможно, мы можем создать элемент управления в визуальном слое, но я не знаком с ним.
Вы можете создать слой Adorner и добавить к нему элемент управления «обложкой».
Если вам уже удобно создавать данные пути на лету, чтобы получить область вырезания, это первый шаг. Однако ваш оверлей, хотя он может предотвращать прямые события щелчка / наведения ... он по-прежнему будет разрешать взаимодействие пользователя с клавиатурой с элементами за наложением по умолчанию, такими как Tab / Enter. Таким образом, вам придется либо отключить каждый элемент, как указано в @zackraiyan, либо создать макет таким образом, чтобы вы могли IsHitTestVisible=False целые разделы макета, при этом оставив свой единственный UIElement доступным для требуемых событий отдельно.
@ ChrisW., Спасибо, что указали на свойство IsHittestVisible .. Полностью пропустил
@ChrisW. Я уже пробовал IsHitTestVisible со своим путем, но это не сработало для пути. Это имеет смысл, потому что пути - это просто линии, а не надежный контроль. Итак, новый вопрос: «Как создавать нестандартные формы без контуров?»
Нет, вы бы применили его к родительскому контейнеру всех UIElements, и все дочерние UIElements этого контейнера автоматически игнорировали бы все события попадания. Оверлей не заботится о том, что находится под ним в порядке DOM, но родительская панель будет управлять своими дочерними элементами.
@zackraiyan о да, однажды я узнал об этом на собственном горьком опыте, когда наличие тонны элементов, ищущих изменение свойства, вызывало большую проблему с производительностью до тех пор, пока один bool на родительском hittestvisibility не имел огромного значения ... Теперь, если вы спросите меня, где мой ключи от машины могут быть, я, вероятно, не был бы таким полезным, потому что половину времени я понятия не имею, лол
Почему бы не пойти со смесью?





Вместо того, чтобы пытаться получить элемент, который является «переходящим по клику», вы можете просто вывести элемент (в вашем случае кнопку-переключатель) на передний план (в основном над всем остальным, чтобы он был доступен для нажатия). Вы можете сделать это одним из следующих способов:
YourElement.SetValue(Canvas.ZIndexProperty, index);Удалите элемент и снова добавьте его в родительскую сетку (таким образом, это будет последний добавляемый элемент).
parentGrid.Children.Remove(YourElement);
parentGrid.Children.Add(YourElement);
parentGrid.UpdateLayout();
После того, как пользователь успешно взаимодействует с элементом управления, вы можете вернуть его в прежнее состояние. Надеюсь, это поможет ..
Ожидайте выделенного элемента, взаимодействие для всех элементов должно быть отключено. Кроме того, я хочу создать настраиваемый элемент управления.
Я думаю, вы уже достаточно близко подошли к своему примеру, по крайней мере, я не могу найти в нем ничего плохого. Если вы попробуете следующий код, вы увидите, что он делает именно то, что вы описали:
<Grid>
<Button Content = "Clickable" HorizontalAlignment = "Left"
Margin = "113,90,0,0" VerticalAlignment = "Top" Width = "75"/>
<Button Content = "Non-Clickable" HorizontalAlignment = "Left"
Margin = "272,90,0,0" VerticalAlignment = "Top" Width = "75"/>
<Path Name = "ShowcasePath" StrokeThickness = "1" Fill = "#88ff0000" IsHitTestVisible = "True">
<Path.Data>
<GeometryGroup FillRule = "EvenOdd">
<EllipseGeometry Center = "150,100" RadiusX = "100" RadiusY = "50"/>
<RectangleGeometry Rect = "0,0,500,500"/>
</GeometryGroup>
</Path.Data>
</Path>
</Grid>
Однако имейте в виду, что пользователи все равно могут изменить фокусируемый элемент с помощью Tab и активировать элементы с помощью Space или Return, даже если вы установите IsHitTestVisible на false.
Функциональность "сфокусировать эллипс на элементе" может быть легко реализована следующим образом:
public void FocusOnElement(FrameworkElement element)
{
Point center = new Point(element.ActualWidth / 2, element.ActualHeight / 2);
Point newPosition = element.TranslatePoint(center, ShowcasePath);
ellipseGeometry.Center = newPosition;
}
О включении / отключении всех других функций лучше всего позаботиться в вашей модели просмотра, или, если у вас ее нет, примерно так:
private void DiableAllButThisAndItsParents(FrameworkElement thisElement)
{
List<FrameworkElement> hierarchy = FindParents(thisElement).ToList();
foreach (FrameworkElement element in hierarchy)
{
element.IsEnabled = true;
if (ReferenceEquals(element, thisElement)) continue;
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++)
{
var child = VisualTreeHelper.GetChild(element, i);
if (!(child is FrameworkElement childElement)) continue;
childElement.IsEnabled = hierarchy.Contains(childElement);
}
}
}
private IEnumerable<FrameworkElement> FindParents(FrameworkElement element)
{
DependencyObject current = element;
while (current != null)
{
if (current is FrameworkElement)
yield return (FrameworkElement) current;
current = VisualTreeHelper.GetParent(current);
}
}
Сложите все это вместе, и это должно выглядеть примерно так:
Я не хочу связываться с IsEnabled, потому что это изменит внешний вид
@VijayNirmal Ну, конечно, вы можете использовать любую комбинацию техник, упомянутых выше.
IsHitTestVisible работает исправно. Вчера не сработало. Но другая проблема с моим подходом заключается в том, что каждый элемент управления внутри эллипса неразрешим. Предположим, у меня есть кнопка 1 и кнопка 2 рядом друг с другом, тогда, даже если кнопка 1 выделена, мы все равно можем нажать кнопку 2.
Этот гигантский красный ящик действительно режет глаза!