adsl club

Справочник

Форум

Программы

Фильмы

Ресурсы

Файлообмен

Хостинг

Ростелеком
C#. WPF. Как закрыть окно (форму) по клику на дочернем (с большой вложенностью потомков) элементе этого окна.
На страницу 1 2
Ответить на тему    Форум АДСЛ КлубаЦИФРОВОЙ ФЛЕЙМ :)ПРОГРАММИРОВАНИЕ
Автор Сообщение
AlexRock
Гуру
СообщениеДобавлено: Вт 15-12-09 : 16-00    Заголовок сообщения: Ответить с цитатой

Wega писал(а):
1. Почему нельзя где-нибудь запомнить дочернее окно, которое надо закрыть?

Код:
Object parent = current;
while(parent not instanceof Window) {
    parent = parent.getParent();
}
parent.close();

Оба твоих подхода подразумевают, что нужно создать объкт уровня экземпляра класса моего родительского окна, чтобы хранить в этом объекте дочернее окно, тогда это дочернее окно будет доступно во в родительском окне и во всех его элементах содержимого (контролах) с любой вложенносью, а также во всех обработчиках всех этих контролов. Так? Но дело в том, что для этого нужно всё таки создать этот "объект хранения". В этом случае, думаю, создать указатель на дочернее окно будет компактнее (хранить не копию всего окна, как ты предлагал, а только адрес первой ячейки памяти, с которой это окно начинается), а суть будет та же. Я же хочу без создания дополнительных объектов всё делать.
 Наверх
Посмотреть профиль / Отправить личное сообщение Отправить личное сообщение  
Wega
Гуру
СообщениеДобавлено: Вт 15-12-09 : 16-14    Заголовок сообщения: Ответить с цитатой

AlexRock
Нет. Процитированный код в этом не нуждается. Это твой иерархический вариант, но более универсальный. И вообще цитата неправильная: этот код не относится к первому пункту.

Вот код более близкий к твоему:
Код:
void infoDoc_MouseDown(object sender, RoutedEventArgs e) {
    Object p = sender;
    while(!(p is Window)) {
        p = p.Parent;
    }
    p.close();
}

Со скидкой на моё знание c#.
Позволяет не заботиться о глубине вложенности элементов, не порождая дополнительные сущности.
А остальные варианты (карта, класс), да, требуют создания новых объектов.
 Наверх
Посмотреть профиль / Отправить личное сообщение Отправить личное сообщение  
AlexRock
Гуру
СообщениеДобавлено: Вт 15-12-09 : 16-33    Заголовок сообщения: Ответить с цитатой

Aprelle писал(а):
Так я тебе и объясняю, что более очевидно делать по дереву не снизу вверх, а сверху вниз, собственно, обычно так и делают, разве что бывает выносят это в отдельную функцию.

Aprelle писал(а):
наверняка там есть дерево иерархии, по которому можно вытянуть дочерние объекты.

Так что начиная от Application, или основного окна (смотри по дереву, куда оно там прикреплено) можно через .Items() или .getItem() или .getItembyId() сделать нечто типа Application.Windows.Items("infoWindow").Close();

Так нельзя. Во-первых, главное окно программы (это родительское окно для дочернего, которое нужно закрыть) не имеет имени (ну, что поделать - так по умолчанию Вижак создаёт окна (окно = форма в WPF)). lol Но это не важно - даже, если я дам ему имя, то на самом деле у дочернего окна нет предка lol :



Тут перепутались несколько понятий наследования. Главное (родительское) окно у меня ПОРОЖДАЕТ в своём коде дочернее, но дочернее окно НЕ ВЛОЖЕНО в главное - т. е. в смысле вложения оно не дочернее, а самостоятельное. Поэтому спуститься вниз по вложенности элементов не получится.

При этом интересно, что, если в коде обработчика любого элемента дочернего окна вызвать метод Close(), тупо написал "Close();" (без всяких дополнительных объектов и пр.), то закроется главное окно программы, родительское к дочернему в смысле порождения (а не вложенности).
AlexRock писал(а):
Я сейчас с маршрутизируемыми событиями разбираюсь - в них ключ. Только надо пока отследить, чтобы нужный мне объект (дочернее окно, а не все более нижние элементы) отработал это событие.

Ничего не помогло - событие маршрутизируется (т. е. возникает во FlowDocument, а обрабатывается во всех элементах выше по иерархии, вплоть до дочернего окна), но я не могу получить само дочернее окно ни на одном из этапов маршрута этого события, чтобы вызвать функцию Close() для дочернего окна:

Код:
void buttonCell_Click(object sender, RoutedEventArgs e)
{

Window infoWindow = new Window();
infoWindow.MouseDown += new MouseButtonEventHandler(infoDoc_MouseDown);

StackPanel panel = new StackPanel();
panel.MouseDown += new MouseButtonEventHandler(infoDoc_MouseDown);

FlowDocumentScrollViewer FDR = new FlowDocumentScrollViewer();
FDR.MouseDown += new MouseButtonEventHandler(infoDoc_MouseDown);

FlowDocument infoDoc = new FlowDocument();
infoDoc.MouseDown += new MouseButtonEventHandler(infoDoc_MouseDown);

FDR.Document = infoDoc;
panel.Children.Add(FDR);
infoWindow.Content = panel;
infoWindow.ShowDialog();

}


void infoDoc_MouseDown(object sender, RoutedEventArgs e)
{
           
sender.   // а дальше непонятно - либо опять приводить типы, либо... а с четырьмя функциями object не развернёшься.

}




Такое, как на рис. ниже, тоже не получится - при клике на дочернем окне оно не хочет закрываться, хотя проверка типа выполнена правильно (код "sender.GetType().ToString()" возвращает точно такую строку для окна - "System.Windows.Window"):

 Наверх
Посмотреть профиль / Отправить личное сообщение Отправить личное сообщение  
Wega
Гуру
СообщениеДобавлено: Вт 15-12-09 : 16-43    Заголовок сообщения: Ответить с цитатой

AlexRock
Вообще-то проверка типа должна выполняться иначе. Как я понимаю, в c# - это is.
Кстати, в моём примере выше и предполагается, что все элементы GUI наследуют от одного класса, который имеет parent.
 Наверх
Посмотреть профиль / Отправить личное сообщение Отправить личное сообщение  
AlexRock
Гуру
СообщениеДобавлено: Вт 15-12-09 : 16-44    Заголовок сообщения: Ответить с цитатой

Wega писал(а):
Вот код более близкий к твоему:

Wega писал(а):
p = p.Parent;

Как я уже написал, предка у моего дочернего окна нет (null-ссылка возвращается), поэтому не пройдёт.

Wega писал(а):
Вообще-то проверка типа должна выполняться иначе. Как я понимаю, в c# - это is.

Два похожих варианта тоже не проходят:


уже упомянутый


здесь вообще смешно - сначала делается проверка, а потом приведение lol
Последний раз редактировалось: AlexRock (Вт 15-12-09 : 16-46), всего редактировалось 2 раз(а)
 Наверх
Посмотреть профиль / Отправить личное сообщение Отправить личное сообщение  
Aprelle
Гуру
СообщениеДобавлено: Вт 15-12-09 : 16-44    Заголовок сообщения: Ответить с цитатой

Цитата:
Так нельзя. Во-первых, главное окно программы (это родительское окно для дочернего, которое нужно закрыть) не имеет имени (ну, что поделать - так по умолчанию Вижак создаёт окна (окно = форма в WPF)). Но это не важно - даже, если я дам ему имя, то на самом деле у дочернего окна нет предка

Ну не от окна дерево вести, так от Апликэйшн, или еще от какого мэйн, не суть важно, факт в том, что я глубоко сомневаюсь, что дочернее окно не стыкуется в иерархии приложения к единому корню программы.
Хотя хрен с ним, действительно нужно плясать от сендера, в принципе через паренты тоже можно, просто чуть более умными методами и с выборкой по Item(), но так тоже сойдет.
Без живого дебаггинга кода мне сложно что-то советовать, так что завязываю флуд со своей стороны.
 Наверх
Посмотреть профиль / Отправить личное сообщение Отправить личное сообщение  
Wega
Гуру
СообщениеДобавлено: Вт 15-12-09 : 16-48    Заголовок сообщения: Ответить с цитатой

AlexRock писал(а):
Как я уже написал, предка у моего дочернего окна нет (null-ссылка возвращается), поэтому не пройдёт.

Если это работает
Код:
((Window)((StackPanel)((FlowDocumentScrollViewer)((FlowDocument)sender).Parent).Parent).Parent).Close();

и есть общий базовый класс с .Parent, то пройдёт. Здесь же ничего по null не вываливается?
Вариант sender is Window - тоже не будет работать, если sender кнопка. Он же кнопка?
 Наверх
Посмотреть профиль / Отправить личное сообщение Отправить личное сообщение  
AlexRock
Гуру
СообщениеДобавлено: Вт 15-12-09 : 17-10    Заголовок сообщения: Ответить с цитатой

Wega писал(а):
Кстати, в моём примере выше и предполагается, что все элементы GUI наследуют от одного класса, который имеет parent.

Тут свойство Parent содержит родителя по вложенности объектов (объекты - как контейнеры для других объектов - логическое дерево наследования), а не по наследованию классов. По наследованию классов двигаться - это зачем и к чему привести должно? Или я что-то не так понял?
Aprelle писал(а):
Ну не от окна дерево вести, так от Апликэйшн, или еще от какого мэйн, не суть важно, факт в том, что я глубоко сомневаюсь, что дочернее окно не стыкуется в иерархии приложения к единому корню программы.

Да, там есть какие-то функции получения визуального родителя или потомка, а также получения какого-то "альтернативного логического родителя, если визуального родителя не существует"



, но это для меня ещё незнакомо.

Я же хотел, чтобы мне что-нибудь готовое дали или подсказали, но конкретнее - я вот только такой тупой код приведения типов придумал, как я в начале написал - на большее меня пока в C# и WPF не хватает. Ваши подсказки по двежению по деревьям мне понятны по логике, но как это сделать конкретно в С# я не знаю.

Хммм, поспрашаю ещё на других форумах...
 Наверх
Посмотреть профиль / Отправить личное сообщение Отправить личное сообщение  
AlexRock
Гуру
СообщениеДобавлено: Вт 15-12-09 : 17-26    Заголовок сообщения: Ответить с цитатой

Wega писал(а):
Вариант sender is Window - тоже не будет работать, если sender кнопка. Он же кнопка?

Нет, отправитель FlowDocument, хотя может быть любой вообще объект - я же могу захотеть закрыть окно по щелчке по любому объекту.
Wega писал(а):
и есть общий базовый класс с .Parent, то пройдёт

Ну, я уже выше ответил - зачем по иерархии классов-то идти вверх? До какого класса? У меня уже сразу есть object в качестве отправителя (как ссылка на отправителя - FlowDocument) - базовый класс для ВСЕХ элементов и у него только четыре функции. Вот я этот object и привожу к нужному мне объекту и далее уже по ЛОГИЧЕСКОМУ дереву (через Parent) вверх, к окну.

Я вот чего не пойму - почему при таком варианте (при любом способе - что с this, что без него):



закрывается РОДИТЕЛЬСКОЕ ОКНО - главное окно приложения моего? Ведь событие возникло в элементе ДОЧЕРНЕГО окна! Ап стену друже!


Функция FindName тоже выдаёт null, хотя я использую её от родительского окна:

 Наверх
Посмотреть профиль / Отправить личное сообщение Отправить личное сообщение  
Wega
Гуру
СообщениеДобавлено: Вт 15-12-09 : 17-57    Заголовок сообщения: Ответить с цитатой

AlexRock
По иерархии объектов от sender'а (панельки) до класса Window (окно, которое этот sender содержит). Идём от sender'а до основного окна по .parent и как только .parent is Window - close.
Если в .net это возможно. В Java/Swing такой способ работаёт чётко. Более того, там это уже в библиотеках реализовано - для любого элемента гуи можно запросить окно. Хотел предложить похожий способ для твоего случая, но похоже, надо лезть в MSDN, чтобы проверить его работоспособность, а мне лень. А тебе объяснить у меня не получается.

AlexRock писал(а):
закрывается РОДИТЕЛЬСКОЕ ОКНО - главное окно приложения моего? Ведь событие возникло в элементе ДОЧЕРНЕГО окна!
Но обработчик то находится в классе главного окна! Если я правильно понимаю. Указатель this явный или неявный будет ссылаться на объект класса, а не на что-то там куда ты передаёшь этот обработчик.
 Наверх
Посмотреть профиль / Отправить личное сообщение Отправить личное сообщение  
AlexRock
Гуру
СообщениеДобавлено: Вт 15-12-09 : 20-12    Заголовок сообщения: Ответить с цитатой

Wega писал(а):
Но обработчик то находится в классе главного окна! Если я правильно понимаю.

Да, точно... Хоть новый класс создавай специально для этого дочернего окошка.
Wega писал(а):
По иерархии объектов от sender'а (панельки) до класса Window (окно, которое этот sender содержит). Идём от sender'а до основного окна по .parent и как только .parent is Window - close.

Если в .net это возможно.

Дело в том, что у меня, после того, как я отмаршрутизировал событие MouseDown (всем событиям по дереву элементов от FlowDocument, где оно возникает, до дочернего Window, в котором вся компоновка с FlowDocument находится, приделал для события MouseDown один и тот же обработчик), у меня sender постоянно меняет объект, на который он ссылается. Вот, у меня четыре вложенных элемента:
Код:
Window
    StackPanel
        FlowDocumentScrollViewer
            FlowDocument

и sender меняется от FlowDocument до Window, а обработчик для MouseDown вызывается четыре раза - если, например, сделать вывод через MessageBox.Show(sender.ToString()), то сообщение четыре раза появится и каждый раз с разным типом элемента. Так вот, следующий код не работает (ничего не происходит), хотя по идее должен:



Вообще, непонятно, зачем приводить к Window, если sender уже Window по условиям проверки, но просто компилятор ругается, если я приведение не сделаю. Однако во время выполнения без всякого приведения через MessageBox.Show(sender.ToString() исправно выводится:

System.Windows.Documents.FlowDocument
System.Windows.Controls.FlowDocumentScrollViewer
System.Windows.Cintrols.StackPanel
System.Windows.Window

Т. е. событие поднялось из документа до окна, и sender в конце - уже окно! Тут бы его и закрыть, а вот фиг. ((
 Наверх
Посмотреть профиль / Отправить личное сообщение Отправить личное сообщение  
Estet
Форумчанин
СообщениеДобавлено: Вт 15-12-09 : 20-38    Заголовок сообщения: Ответить с цитатой

Не знаю работает ли применительно к WPF, но для Windows Forms можно использовать такую конструкцию:

private void Btn_Click(object sender, EventArgs e)
{
ActiveForm.Close();
}
 Наверх
Посмотреть профиль / Отправить личное сообщение Отправить личное сообщение  
AlexRock
Гуру
СообщениеДобавлено: Вт 15-12-09 : 21-13    Заголовок сообщения: Ответить с цитатой

Так, я тут ступил (не знаю фреймворка и WPF - что поделать Ап стену друже! ) - тут кто-то говорил, что можно получить хозяйское окно для любого элемента этого окна. Так и сделал и тогда уже закрыл это окно:
Код:
void infoDoc_MouseDown(object sender, RoutedEventArgs e)
{
    GetWindow((FlowDocument)sender).Close();
}

Вот это то, что надо! Даже без маршрутов события обошлось (не надо было к каждому элементу по обработчику прекреплять). Всем спасибо. ))


...Впрочем, GetWindow() наверняка какую-нибудь подобную муть внутри себя мутит, типа моих длинных приведений типов, так что я вроде как всего лишь короткой записью воспользовался.
 Наверх
Посмотреть профиль / Отправить личное сообщение Отправить личное сообщение  
Показать сообщения:   
Ответить на тему    Форум АДСЛ КлубаЦИФРОВОЙ ФЛЕЙМ :)ПРОГРАММИРОВАНИЕ Часовой пояс: GMT + 7
На страницу 1 2
Страница 2 из 2

 

 
Аватары: Вкл|Выкл   ЮзерИнфо: Вкл|Выкл   Подписи: Вкл|Выкл
Перейти:  
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете вкладывать файлы
Вы можете скачивать файлы